configlet lint


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.

Uso

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]

Regras

Estas são as regras de verificação que são checadas.

Regra: os arquivos obrigatórios estão presentes

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.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 arquivos específicos de exercícios de conceito que devem 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 arquivos:

  • concepts/<slug>/about.md
  • concepts/<slug>/introduction.md
  • concepts/<slug>/links.json

Regra: o arquivo config.json é válido

O arquivo config.json deve passar pelas seguintes verificações:

  • O arquivo deve ser um JSON válido
  • A chave "language" é obrigatória
  • O valor de "language" deve ser uma string não vazia¹ com comprimento <= 255
  • A chave "slug" é obrigatória
  • O valor de "slug" deve ser uma string em kebab-case² com comprimento <= 255
  • A chave "active" é obrigatória
  • O valor de "active" deve ser um Boolean
  • A chave "blurb" é obrigatória
  • O valor de "blurb" deve ser uma string não vazia¹ com comprimento <= 400
  • A chave "version" é obrigatória
  • O valor de "version" deve ser o inteiro 3
  • A chave "status.concept_exercises" é obrigatória
  • O valor de "status.concept_exercises" deve ser um Boolean
  • A chave "status.test_runner" é obrigatória
  • O valor de "status.test_runner" deve ser um Boolean
  • A chave "status.representer" é obrigatória
  • O valor de "status.representer" deve ser um Boolean
  • A chave "status.analyzer" é obrigatória
  • O valor de "status.analyzer" deve ser um Boolean
  • A chave "online_editor.indent_style" é obrigatória
  • O valor de "online_editor.indent_style" deve ser a string space ou tab
  • A chave "online_editor.indent_size" é obrigatória
  • O valor de "online_editor.indent_size" deve ser um inteiro >= 0 e <= 8
  • A chave "online_editor.highlightjs_language" é opcional
  • O valor de "online_editor.highlightjs_language" deve ser uma string não vazia¹
  • A chave "files" é opcional
  • O valor de "files" deve ser um objeto
  • A chave "files.solution" é opcional
  • O valor de "files.solution" deve ser um array
  • Os valores de "files.solution" devem ser padrões válidos⁵
  • Os valores de "files.solution" não podem ter duplicatas
  • A chave "files.test" é opcional
  • O valor de "files.test" deve ser um array
  • Os valores de "files.test" devem ser padrões válidos⁵
  • Os valores de "files.test" não podem ter duplicatas
  • A chave "files.example" é opcional
  • O valor de "files.example" deve ser um array
  • Os valores de "files.example" devem ser padrões válidos⁵
  • Os valores de "files.example" não podem ter duplicatas
  • A chave "files.exemplar" é opcional
  • O valor de "files.exemplar" deve ser um array
  • Os valores de "files.exemplar" devem ser padrões válidos⁵
  • Os valores de "files.exemplar" não podem ter duplicatas
  • A chave "files.editor" é opcional
  • O valor de "files.editor" deve ser um array
  • Os valores de "files.editor" devem ser padrões válidos⁵
  • Os valores de "files.editor" não podem ter duplicatas
  • A chave "files.invalidator" é opcional
  • O valor de "files.invalidator" deve ser um array
  • Os valores de "files.invalidator" devem ser padrões válidos⁵
  • Os valores de "files.invalidator" não podem ter duplicatas
  • Os padrões só podem ser listados em um dos arrays "files.solution", "files.test", "files.example", "files.exemplar", "files.editor" ou "files.invalidator" (sem sobreposição)
    • Se a track for d ou plsql, os arquivos "files.solution" e "files.test" podem se sobrepor
    • Os arquivos "files.example e "files.exemplar" podem se sobrepor
  • 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" deve ser um inteiro > 0
  • A chave "approaches.snippet_extension" é obrigatória se a track tiver uma ou mais abordagens
  • O valor de "approaches.snippet_extension" deve ser uma string não vazia¹
  • A chave "exercises" é obrigatória
  • A chave "exercises.concept" é obrigatória
  • O valor de "exercises.concept" deve ser um array
  • A chave "exercises.concept[].slug" é obrigatória
  • O valor de "exercises.concept[].slug" deve ser uma string em kebab-case² com comprimento <= 255
  • O valor de "exercises.concept[].slug" deve 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" deve ser uma string em Title Case³ com comprimento <= 255
  • A chave "exercises.concept[].uuid" é obrigatória
  • O valor de "exercises.concept[].uuid" deve ser uma string UUID 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" deve ser um array não vazio de strings se "exercises.concept[].status" não for igual a deprecated
  • O valor de "exercises.concept[].concepts" deve ser um array vazio se "exercises.concept[].status" for igual a deprecated
  • Os valores de "exercises.concept[].concepts" devem ser strings em kebab-case²
  • Os valores de "exercises.concept[].concepts" não podem ter duplicatas
  • Os valores de "exercises.concept[].concepts" não podem estar na propriedade "concepts" de nenhum outro exercício de conceito
  • Os valores de "exercises.concept[].concepts" devem corresponder à propriedade "concepts.slug" de um dos conceitos
  • A chave "exercises.concept[].prerequisites" é obrigatória
  • O valor de "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
  • O valor de "exercises.concept[].prerequisites" deve ser um array vazio se "exercises.concept[].status" for igual a deprecated
  • Os valores de "exercises.concept[].prerequisites" devem ser strings em kebab-case²
  • Os valores de "exercises.concept[].prerequisites" não podem ter duplicatas
  • Os valores de "exercises.concept[].prerequisites" devem 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" devem 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" deve ser a string wip, beta, active ou deprecated
  • A chave "exercises.practice" é obrigatória
  • O valor de "exercises.practice" deve ser um array
  • A chave "exercises.practice[].slug" é obrigatória
  • O valor de "exercises.practice[].slug" deve ser uma string em kebab-case² com comprimento <= 255
  • O valor de "exercises.practice[].slug" deve ser único em "exercises.practice[].slug" e não pode existir em "exercises.concept[].slug"
  • Deve 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" deve ser uma string em Title Case³ com comprimento <= 255
  • A chave "exercises.practice[].uuid" é obrigatória
  • O valor de "exercises.practice[].uuid" deve ser uma string UUID 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" deve ser um inteiro >= 1 e <= 10
  • A chave "exercises.practice[].practices" é obrigatória
  • O valor de "exercises.practice[].practices" deve ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
  • O valor de "exercises.practice[].practices" deve ser um array vazio se "exercises.practice[].status" for igual a deprecated
  • Os valores de "exercises.practice[].practices" devem ser strings em kebab-case²
  • Os valores de "exercises.practice[].practices" não podem ter duplicatas
  • Os valores de "exercises.practice[].practices" devem corresponder à propriedade "concepts[].slug" de um dos conceitos
  • Os valores de "exercises.practice[].practices" devem se referir ao slug de um conceito individual no máximo 10 vezes (considerando todos os exercícios)
  • A chave "exercises.practice[].prerequisites" é obrigatória
  • O valor de "exercises.practice[].prerequisites" deve ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
  • O valor de "exercises.practice[].prerequisites" deve ser um array vazio se "exercises.practice[].status" for igual a deprecated
  • O valor de "exercises.practice[].prerequisites" deve ser um array vazio se "exercises.practice[].slug" for igual a hello-world
  • Os valores de "exercises.practice[].prerequisites" devem ser strings em kebab-case²
  • Os valores de "exercises.practice[].prerequisites" não podem ter duplicatas
  • Os valores de "exercises.practice[].prerequisites" devem corresponder aos valores de "exercises.concept[].concepts" de algum exercício de conceito
  • Os valores de "exercises.practice[].prerequisites" devem corresponder à propriedade "concepts[].slug" de um dos conceitos
  • A chave "exercises.practice[].status" é opcional
  • O valor de "exercises.practice[].status" deve ser a string wip, beta, active ou deprecated
  • O valor de "exercises.practice[].status", se "exercises.practice[].slug" for igual a hello-world, deve ser omitido ou ser a string active
  • A chave "exercises.foregone" é opcional
  • O valor de "exercises.foregone" deve ser um array
  • Os valores de "exercises.foregone" devem ser strings em kebab-case²
  • Os valores de "exercises.foregone" não podem ter duplicatas
  • Os valores de "exercises.foregone" não podem corresponder a nenhum dos slugs de exercícios de conceito ou de prática
  • A chave "concepts" é obrigatória
  • O valor de "concepts" deve ser um array
  • A chave "concepts[].uuid" é obrigatória
  • O valor de "concepts[].uuid" deve ser uma string UUID 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" deve ser uma string em kebab-case² com comprimento <= 255
  • A chave "concepts[].name" é obrigatória
  • O valor de "concepts[].name" deve 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 vazia
  • O valor de "concepts[].tags.all" deve ser um array
  • Os valores de "concepts[].tags.all" devem ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "concepts[].tags.all" não podem ter duplicatas
  • A chave "concepts[].tags.any" é opcional, a menos que "concepts[].tags.all" esteja vazia
  • O valor de "concepts[].tags.any" deve ser um array
  • Os valores de "concepts[].tags.any" devem ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "concepts[].tags.any" não podem ter duplicatas
  • A chave "concepts[].tags.not" é opcional
  • O valor de "concepts[].tags.not" deve ser um array
  • Os valores de "concepts[].tags.not" devem ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "concepts[].tags.not" não podem ter duplicatas
  • Cada valor de "concepts" deve ter um arquivo concept/<concepts.slug>/about.md. As regras de verificação para esse arquivo estão especificadas abaixo.
  • Cada valor de "concepts" deve ter um arquivo concept/<concepts.slug>/introduction.md. As regras de verificação para esse arquivo estão especificadas abaixo.
  • Cada valor de "concepts" deve ter um arquivo concept/<concepts.slug>/links.json. As regras de verificação para esse arquivo estão especificadas abaixo.
  • A chave "key_features" é opcional
  • O valor de "key_features" deve ser um array com comprimento = 6
  • A chave "key_features[].icon" é obrigatória
  • O valor de "key_features[].icon" deve usar um dos valores de ícone predefinidos
  • A chave "key_features[].title" é obrigatória
  • O valor de "key_features[].title" deve ser uma string em Sentence Case⁴ com comprimento <= 25
  • A chave "key_features[].content" é obrigatória
  • O valor de "key_features[].content" deve ser uma string não vazia¹ com comprimento <= 100
  • A chave "tags" é obrigatória
  • O valor de "tags" deve ser um array de strings
  • Os valores de "tags" não podem ter duplicatas
  • Os valores de "tags" devem usar um dos valores de tag predefinidos

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

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

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

  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Todos os títulos devem ser ## General ou ## X. <task>, em que X corresponde ao título do número da tarefa em instructions.md
  • Todas as dicas devem ser especificadas como itens de lista Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Todas as tarefas devem começar com um título de nível dois que começa com um número seguido de um ponto: ## 1. Do X
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • O conceito de cada placeholder de conceito deve corresponder à propriedade "concepts.slug" de um dos conceitos no config.json da track.

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

  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • O arquivo deve ser um JSON válido
  • A raiz do JSON deve ser um objeto
  • A chave "blurb" é obrigatória
  • O valor de "blurb" deve ser uma string não vazia¹ com comprimento <= 350
  • A chave "source" é opcional
  • O valor de "source" deve ser uma string não vazia¹
  • A chave "source_url" é opcional
  • O valor de "source_url" deve ser uma URL
  • A chave "authors" é opcional
  • O valor de "authors" deve ser um array
  • Os valores de "authors" devem ser strings não vazias¹
  • Os valores de "authors" não podem ter duplicatas
  • Os valores de "authors" são tratados sem diferenciar maiúsculas de minúsculas
  • A chave "contributors" é opcional
  • O valor de "contributors" deve ser um array
  • Os valores de "contributors" devem ser strings não vazias¹
  • Os valores de "contributors" não podem ter duplicatas
  • Os valores de "contributors" são tratados sem diferenciar maiúsculas de minúsculas
  • Os usuários só podem ser listados em um dos arrays "authors" ou "contributors" (sem sobreposição)
  • A chave "files.solution" é obrigatória
  • O valor de "files.solution" deve ser um array não vazio
  • Os valores de "files.solution" não podem ter duplicatas
  • A chave "files.test" é obrigatória
  • O valor de "files.test" deve ser um array não vazio
  • Os valores de "files.test" não podem ter duplicatas
  • A chave "files.example" é obrigatória
  • O valor de "files.example" deve ser um array não vazio
  • Os valores de "files.example" não podem ter duplicatas
  • A chave "files.editor" é opcional
  • O valor de "files.editor" deve ser um array
  • Os valores de "files.editor" não podem ter duplicatas
  • A chave "files.invalidator" é opcional
  • O valor de "files.invalidator" deve ser um array
  • Os valores de "files.invalidator" não podem ter duplicatas
  • Os arquivos listados em "files.solution" devem existir
  • Os arquivos listados em "files.test" devem existir
  • Os arquivos listados em "files.example" devem existir
  • Os arquivos listados em "files.editor" devem existir
  • Os arquivos listados em "files.invalidator" devem existir
  • Os arquivos só podem ser listados em um dos arrays "files.solution", "files.test", "files.example ou "files.invalidator" (sem sobreposição)
    • Se a track for d ou plsql, os arquivos "files.solution" e "files.test" podem se sobrepor
  • A chave "language_versions" é opcional
  • O valor de "language_versions" deve ser uma string
  • A chave "test_runner" é opcional
  • O valor de "test_runner" deve ser um Boolean
  • A chave "representer.version" é opcional
  • O valor de "representer.version" deve ser um inteiro >= 1
  • A chave "icon" é opcional
  • O valor de "icon" deve ser uma string em kebab-case²

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

  • A presença do arquivo é opcional, a menos que exista um introduction.md ou um diretório irmão
  • O arquivo deve ser um JSON válido
  • A raiz do JSON deve ser um objeto
  • A chave "introduction.authors" é opcional
  • O valor de "introduction.authors" deve ser um array
  • Os valores de "introduction.authors" devem ser strings não vazias¹
  • Os valores de "introduction.authors" não podem ter duplicatas
  • Os valores de "introduction.authors" são tratados sem diferenciar maiúsculas de minúsculas
  • Se o array "introduction.authors" não estiver vazio, deve haver um arquivo introduction.md não vazio
  • A chave "introduction.contributors" é opcional
  • O valor de "introduction.contributors" deve ser um array
  • Os valores de "introduction.contributors" devem ser strings não vazias¹
  • Os valores de "introduction.contributors" não podem ter duplicatas
  • Os valores de "introduction.contributors" são tratados sem diferenciar maiúsculas de minúsculas
  • Se o array "introduction.contributors" não estiver vazio, deve haver um arquivo introduction.md não vazio
  • Os usuários só podem ser listados em um dos arrays "introduction.authors" ou "introduction.contributors" (sem sobreposição)
  • A chave "approaches" é opcional, a menos que exista um diretório irmão presente (que contém os arquivos da abordagem)
  • O valor de "approaches" deve ser um array de objetos
  • A chave "approaches[].uuid" é obrigatória
  • O valor de "approaches[].uuid" deve ser uma string UUID 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" deve ser uma string em kebab-case² com comprimento <= 255
  • O valor de "approaches[].slug" deve ter um arquivo <slug>/content.md não vazio correspondente
  • O valor de "approaches[].slug" deve ter um arquivo <slug>/snippet.txt não vazio correspondente
  • A chave "approaches[].title" é obrigatória
  • O valor de "approaches[].title" deve ser uma string em Title Case³ com comprimento <= 255
  • A chave "approaches[].blurb" é obrigatória
  • O valor de "approaches[].blurb" deve ser uma string não vazia¹ com comprimento <= 350
  • A chave "approaches[].authors" é obrigatória
  • O valor de "approaches[].authors" deve ser um array não vazio
  • Os valores de "approaches[].authors" devem ser strings não vazias¹
  • Os valores de "approaches[].authors" não podem ter duplicatas
  • Os valores de "approaches[].authors" são tratados sem diferenciar maiúsculas de minúsculas
  • A chave "approaches[].contributors" é opcional
  • O valor de "approaches[].contributors" deve ser um array
  • Os valores de "approaches[].contributors" devem ser strings não vazias¹
  • Os valores de "approaches[].contributors" não podem ter duplicatas
  • Os valores de "approaches[].contributors" são tratados sem diferenciar maiúsculas de minúsculas
  • Os usuários só podem ser listados em um 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 vazia
  • O valor de "approaches[].tags.all" deve ser um array
  • Os valores de "approaches[].tags.all" devem ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "approaches[].tags.all" não podem ter duplicatas
  • A chave "approaches[].tags.any" é opcional, a menos que "approaches[].tags.all" esteja vazia
  • O valor de "approaches[].tags.any" deve ser um array
  • Os valores de "approaches[].tags.any" devem ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "approaches[].tags.any" não podem ter duplicatas
  • A chave "approaches[].tags.not" é opcional
  • O valor de "approaches[].tags.not" deve ser um array
  • Os valores de "approaches[].tags.not" devem ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "approaches[].tags.not" não podem ter duplicatas

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

  • A presença do arquivo é obrigatória se existir uma entrada "approaches[].slug" correspondente no arquivo .approaches/config.json
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

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

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

  • A presença do arquivo é opcional, a menos que exista um diretório irmão
  • O arquivo deve ser um JSON válido
  • A raiz do JSON deve ser um objeto
  • A chave "articles" é opcional, a menos que exista um diretório irmão presente (que contém os arquivos do artigo)
  • O valor de "articles" deve ser um array de objetos
  • A chave "articles[].uuid" é obrigatória
  • O valor de "articles[].uuid" deve ser uma string UUID 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" deve ser uma string em kebab-case² com comprimento <= 255
  • O valor de "articles[].slug" deve ter um arquivo <slug>/content.md não vazio correspondente
  • O valor de "articles[].slug" deve ter um arquivo <slug>/snippet.md não vazio correspondente
  • A chave "articles[].title" é obrigatória
  • O valor de "articles[].title" deve ser uma string em Title Case³ com comprimento <= 255
  • A chave "articles[].blurb" é obrigatória
  • O valor de "articles[].blurb" deve ser uma string não vazia¹ com comprimento <= 350
  • A chave "articles[].authors" é obrigatória
  • O valor de "articles[].authors" deve ser um array não vazio
  • Os valores de "articles[].authors" devem ser strings não vazias¹
  • Os valores de "articles[].authors" não podem ter duplicatas
  • Os valores de "articles[].authors" são tratados sem diferenciar maiúsculas de minúsculas
  • A chave "articles[].contributors" é opcional
  • O valor de "articles[].contributors" deve ser um array
  • Os valores de "articles[].contributors" devem ser strings não vazias¹
  • Os valores de "articles[].contributors" não podem ter duplicatas
  • Os valores de "articles[].contributors" são tratados sem diferenciar maiúsculas de minúsculas
  • Os usuários só podem ser listados em um 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 arquivo é obrigatória se existir uma entrada "articles[].slug" correspondente no arquivo .articles/config.json
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • A presença do arquivo é obrigatória se existir uma entrada "articles[].slug" correspondente no arquivo .articles/config.json
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • O snippet deve ter no máximo 8 linhas (os marcadores 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 arquivo é opcional
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • A presença do arquivo é obrigatória
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • A presença do arquivo é obrigatória
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

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

  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)
  • O arquivo deve ser um JSON válido
  • A raiz do JSON deve ser um array
  • A propriedade "[].url" é obrigatória
  • O valor de "[].url" deve ser uma URL
  • A propriedade "[].description" é obrigatória
  • O valor de "[].description" deve ser uma string não vazia¹
  • A propriedade "[].icon_url" é opcional
  • O valor de "[].icon_url" deve ser uma URL

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

  • O arquivo deve ser um JSON válido
  • A raiz do JSON deve ser um objeto
  • A chave "blurb" é obrigatória
  • O valor de "blurb" deve ser uma string não vazia¹ com comprimento <= 350
  • A chave "authors" é obrigatória
  • O valor de "authors" deve ser um array
  • Os valores de "authors" devem ser strings não vazias¹
  • Os valores de "authors" não podem ter duplicatas
  • Os valores de "authors" são tratados sem diferenciar maiúsculas de minúsculas
  • A chave "contributors" é opcional
  • O valor de "contributors" deve ser um array
  • Os valores de "contributors" devem ser strings não vazias¹
  • Os valores de "contributors" não podem ter duplicatas
  • Os valores de "contributors" são tratados sem diferenciar maiúsculas de minúsculas
  • Os usuários só podem ser listados em um dos arrays "authors" ou "contributors" (sem sobreposição)

Regra: docs/ABOUT.md é válido

  • A presença do arquivo é obrigatória
  • O conteúdo do arquivo não pode estar vazio
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

Regra: docs/INSTALLATION.md é válido

  • A presença do arquivo é obrigatória
  • O conteúdo do arquivo não pode estar vazio
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

Regra: docs/LEARNING.md é válido

  • A presença do arquivo é obrigatória
  • O conteúdo do arquivo não pode estar vazio
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

Regra: docs/RESOURCES.md é válido

  • A presença do arquivo é obrigatória
  • O conteúdo do arquivo não pode estar vazio
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

Regra: docs/SNIPPET.txt é válido

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

Regra: docs/TESTS.md é válido

  • A presença do arquivo é obrigatória
  • O conteúdo do arquivo não pode estar vazio
  • O Markdown deve estar em conformidade com os padrões de Markdown
  • Os links devem ser absolutos (links relativos não são permitidos)

Glossário

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

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

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

    • Coloque em maiúscula a primeira e a última palavra de títulos e subtítulos.
    • Coloque em maiúscula as palavras "principais" (substantivos, pronomes, verbos, adjetivos, advérbios e algumas conjunções).
    • Deixe em minúscula as conjunções and, but, for, or e nor.
    • Deixe em minúscula os artigos the, a e an.
    • Deixe em minúscula as preposições, independentemente do comprimento, exceto quando forem enfatizadas, usadas de forma adverbial ou adjetival, ou usadas como conjunções.
    • Deixe em minúscula as palavras to e as.
    • Deixe em minúscula a segunda parte de nomes científicos em latim.
  4. String em Sentence Case: uma string não vazia que segue as diretrizes abaixo:

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

    • Ela existe apenas uma vez no arquivo config.json de nível de track de uma determinada track do Exercism
    • Ela não existe no arquivo config.json de nível de track de nenhuma outra track do Exercism
    • Ela não existe em nenhum arquivo canonical-data.json em https://github.com/exercism/problem-specifications
    • Ela não existe em nenhum outro lugar no Exercism
    • Ela 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
    

    Você pode rodar configlet uuid para gerar um UUID adequado.

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