configlet lint


El uso principal de configlet es el análisis estático: comprobar que los archivos de configuración de un track estén correctamente estructurados, tanto sintáctica como semánticamente. Los tracks mal configurados pueden no sincronizarse correctamente, verse mal en el sitio web o dar una experiencia de usuario poco óptima, así que las comprobaciones de configlet cumplen un papel importante a la hora de mantener la integridad de Exercism.

Uso

El comando lint se puede usar para analizar un 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]

Reglas

Estas son las reglas de análisis estático que se comprueban.

Regla: los archivos requeridos están presentes

El linter debería comprobar que estén presentes todos los archivos requeridos. Los archivos que no son específicos de un ejercicio y que deben estar presentes son:

  • 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

Los archivos específicos de los ejercicios de concepto que deben estar presentes son:

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

Habrá una lista similar para los ejercicios de práctica, pero todavía no hemos definido la especificación para eso.

Cada concepto listado en config.json debería tener los siguientes archivos:

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

Regla: el archivo config.json es válido

El archivo config.json debe superar las siguientes comprobaciones:

  • El archivo debe ser JSON válido
  • La clave "language" es obligatoria
  • El valor de "language" debe ser un string¹ no vacío con una longitud <= 255
  • La clave "slug" es obligatoria
  • El valor de "slug" debe ser un string² en kebab-case con una longitud <= 255
  • La clave "active" es obligatoria
  • El valor de "active" debe ser un Boolean
  • La clave "blurb" es obligatoria
  • El valor de "blurb" debe ser un string¹ no vacío con una longitud <= 400
  • La clave "version" es obligatoria
  • El valor de "version" debe ser el entero 3
  • La clave "status.concept_exercises" es obligatoria
  • El valor de "status.concept_exercises" debe ser un Boolean
  • La clave "status.test_runner" es obligatoria
  • El valor de "status.test_runner" debe ser un Boolean
  • La clave "status.representer" es obligatoria
  • El valor de "status.representer" debe ser un Boolean
  • La clave "status.analyzer" es obligatoria
  • El valor de "status.analyzer" debe ser un Boolean
  • La clave "online_editor.indent_style" es obligatoria
  • El valor de "online_editor.indent_style" debe ser el string space o tab
  • La clave "online_editor.indent_size" es obligatoria
  • El valor de "online_editor.indent_size" debe ser un entero >= 0 y <= 8
  • La clave "online_editor.highlightjs_language" es opcional
  • El valor de "online_editor.highlightjs_language" debe ser un string¹ no vacío
  • La clave "files" es opcional
  • El valor de "files" debe ser un objeto
  • La clave "files.solution" es opcional
  • El valor de "files.solution" debe ser un array
  • Los valores de "files.solution" deben ser patrones⁵ válidos
  • Los valores de "files.solution" no deben tener duplicados
  • La clave "files.test" es opcional
  • El valor de "files.test" debe ser un array
  • Los valores de "files.test" deben ser patrones⁵ válidos
  • Los valores de "files.test" no deben tener duplicados
  • La clave "files.example" es opcional
  • El valor de "files.example" debe ser un array
  • Los valores de "files.example" deben ser patrones⁵ válidos
  • Los valores de "files.example" no deben tener duplicados
  • La clave "files.exemplar" es opcional
  • El valor de "files.exemplar" debe ser un array
  • Los valores de "files.exemplar" deben ser patrones⁵ válidos
  • Los valores de "files.exemplar" no deben tener duplicados
  • La clave "files.editor" es opcional
  • El valor de "files.editor" debe ser un array
  • Los valores de "files.editor" deben ser patrones⁵ válidos
  • Los valores de "files.editor" no deben tener duplicados
  • La clave "files.invalidator" es opcional
  • El valor de "files.invalidator" debe ser un array
  • Los valores de "files.invalidator" deben ser patrones⁵ válidos
  • Los valores de "files.invalidator" no deben tener duplicados
  • Los patrones solo se pueden listar en uno de los arrays "files.solution", "files.test", "files.example", "files.exemplar", "files.editor" o "files.invalidator" (sin solapamiento)
    • Si el track es d o plsql, los archivos de "files.solution" y "files.test" pueden solaparse
    • Los archivos de "files.example y "files.exemplar" pueden solaparse
  • La clave "test_runner.average_run_time" es obligatoria si "status.test_runner" es igual a true
  • El valor de "test_runner.average_run_time" debe ser un entero > 0
  • La clave "approaches.snippet_extension" es obligatoria si el track tiene uno o más enfoques
  • El valor de "approaches.snippet_extension" debe ser un string¹ no vacío
  • La clave "exercises" es obligatoria
  • La clave "exercises.concept" es obligatoria
  • El valor de "exercises.concept" debe ser un array
  • La clave "exercises.concept[].slug" es obligatoria
  • El valor de "exercises.concept[].slug" debe ser un string² en kebab-case con una longitud <= 255
  • El valor de "exercises.concept[].slug" debe ser único en "exercises.concept[].slug" y no puede existir en "exercises.practice[].slug"
  • La clave "exercises.concept[].name" es obligatoria
  • El valor de "exercises.concept[].name" debe ser un string³ en Title Case con una longitud <= 255
  • La clave "exercises.concept[].uuid" es obligatoria
  • El valor de "exercises.concept[].uuid" debe ser un string⁶ de UUID versión 4 único
  • El valor de "exercises.concept[].uuid" de cada ejercicio nunca debe cambiar
  • La clave "exercises.concept[].concepts" es obligatoria
  • El valor de "exercises.concept[].concepts" debe ser un array no vacío de strings si "exercises.concept[].status" no es igual a deprecated
  • El valor de "exercises.concept[].concepts" debe ser un array vacío si "exercises.concept[].status" es igual a deprecated
  • Los valores de "exercises.concept[].concepts" deben ser strings² en kebab-case
  • Los valores de "exercises.concept[].concepts" no deben tener duplicados
  • Los valores de "exercises.concept[].concepts" no deben estar en la propiedad "concepts" de ningún otro ejercicio de concepto
  • Los valores de "exercises.concept[].concepts" deben coincidir con la propiedad "concepts.slug" de uno de los conceptos
  • La clave "exercises.concept[].prerequisites" es obligatoria
  • El valor de "exercises.concept[].prerequisites" debe ser un array no vacío de strings si "exercises.concept[].status" no es igual a deprecated, excepto en exactamente un ejercicio, que sí puede tener un array vacío como valor
  • El valor de "exercises.concept[].prerequisites" debe ser un array vacío si "exercises.concept[].status" es igual a deprecated
  • Los valores de "exercises.concept[].prerequisites" deben ser strings² en kebab-case
  • Los valores de "exercises.concept[].prerequisites" no deben tener duplicados
  • Los valores de "exercises.concept[].prerequisites" deben coincidir con los valores de la propiedad "concepts" de algún otro ejercicio de concepto
  • Los valores de "exercises.concept[].prerequisites" no deben coincidir con ninguno de los valores de la propiedad "exercises.concept[].concepts" del ejercicio
  • Los valores de "exercises.concept[].prerequisites" deben coincidir con la propiedad "concepts.slug" de uno de los conceptos
  • No debe haber ciclos entre "exercises.concept[].concepts" y "exercises.concept[].prerequisites"
  • La clave "exercises.concept[].status" es opcional
  • El valor de "exercises.concept[].status" debe ser el string wip, beta, active o deprecated
  • La clave "exercises.practice" es obligatoria
  • El valor de "exercises.practice" debe ser un array
  • La clave "exercises.practice[].slug" es obligatoria
  • El valor de "exercises.practice[].slug" debe ser un string² en kebab-case con una longitud <= 255
  • El valor de "exercises.practice[].slug" debe ser único en "exercises.practice[].slug" y no puede existir en "exercises.concept[].slug"
  • Debe haber exactamente un valor de "exercises.practice[].slug" que sea el string hello-world
  • La clave "exercises.practice[].name" es obligatoria
  • El valor de "exercises.practice[].name" debe ser un string³ en Title Case con una longitud <= 255
  • La clave "exercises.practice[].uuid" es obligatoria
  • El valor de "exercises.practice[].uuid" debe ser un string⁶ de UUID versión 4 único
  • El valor de "exercises.practice[].uuid" de cada ejercicio nunca debe cambiar
  • La clave "exercises.practice[].difficulty" es obligatoria
  • El valor de "exercises.practice[].difficulty" debe ser un entero >= 1 y <= 10
  • La clave "exercises.practice[].practices" es obligatoria
  • El valor de "exercises.practice[].practices" debe ser un array no vacío de strings si "exercises.practice[].status" no es igual a deprecated
  • El valor de "exercises.practice[].practices" debe ser un array vacío si "exercises.practice[].status" es igual a deprecated
  • Los valores de "exercises.practice[].practices" deben ser strings² en kebab-case
  • Los valores de "exercises.practice[].practices" no deben tener duplicados
  • Los valores de "exercises.practice[].practices" deben coincidir con la propiedad "concepts[].slug" de uno de los conceptos
  • Los valores de "exercises.practice[].practices" deben referirse al slug de un concepto individual como máximo 10 veces (en todos los ejercicios)
  • La clave "exercises.practice[].prerequisites" es obligatoria
  • El valor de "exercises.practice[].prerequisites" debe ser un array no vacío de strings si "exercises.practice[].status" no es igual a deprecated
  • El valor de "exercises.practice[].prerequisites" debe ser un array vacío si "exercises.practice[].status" es igual a deprecated
  • El valor de "exercises.practice[].prerequisites" debe ser un array vacío si "exercises.practice[].slug" es igual a hello-world
  • Los valores de "exercises.practice[].prerequisites" deben ser strings² en kebab-case
  • Los valores de "exercises.practice[].prerequisites" no deben tener duplicados
  • Los valores de "exercises.practice[].prerequisites" deben coincidir con los valores de "exercises.concept[].concepts" de algún ejercicio de concepto
  • Los valores de "exercises.practice[].prerequisites" deben coincidir con la propiedad "concepts[].slug" de uno de los conceptos
  • La clave "exercises.practice[].status" es opcional
  • El valor de "exercises.practice[].status" debe ser el string wip, beta, active o deprecated
  • El valor de "exercises.practice[].status", si "exercises.practice[].slug" es igual a hello-world, debe omitirse o ser el string active
  • La clave "exercises.foregone" es opcional
  • El valor de "exercises.foregone" debe ser un array
  • Los valores de "exercises.foregone" deben ser strings² en kebab-case
  • Los valores de "exercises.foregone" no deben tener duplicados
  • Los valores de "exercises.foregone" no deben coincidir con ninguno de los slugs de los ejercicios de concepto o de práctica
  • La clave "concepts" es obligatoria
  • El valor de "concepts" debe ser un array
  • La clave "concepts[].uuid" es obligatoria
  • El valor de "concepts[].uuid" debe ser un string⁶ de UUID versión 4 único
  • El valor de "concepts[].uuid" de cada concepto nunca debe cambiar
  • La clave "concepts[].slug" es obligatoria
  • El valor de "concepts[].slug" debe ser un string² en kebab-case con una longitud <= 255
  • La clave "concepts[].name" es obligatoria
  • El valor de "concepts[].name" debe ser un string³ en Title Case con una longitud <= 255
  • La clave "concepts[].tags" es opcional
  • La clave "concepts[].tags.all" es opcional, salvo que "concepts[].tags.any" esté vacío
  • El valor de "concepts[].tags.all" debe ser un array
  • Los valores de "concepts[].tags.all" deben ser tags⁷ no vacíos con una longitud <= 255
  • Los valores de "concepts[].tags.all" no deben tener duplicados
  • La clave "concepts[].tags.any" es opcional, salvo que "concepts[].tags.all" esté vacío
  • El valor de "concepts[].tags.any" debe ser un array
  • Los valores de "concepts[].tags.any" deben ser tags⁷ no vacíos con una longitud <= 255
  • Los valores de "concepts[].tags.any" no deben tener duplicados
  • La clave "concepts[].tags.not" es opcional
  • El valor de "concepts[].tags.not" debe ser un array
  • Los valores de "concepts[].tags.not" deben ser tags⁷ no vacíos con una longitud <= 255
  • Los valores de "concepts[].tags.not" no deben tener duplicados
  • Cada valor de "concepts" debe tener un archivo concept/<concepts.slug>/about.md. Las reglas de análisis estático para este archivo se especifican a continuación.
  • Cada valor de "concepts" debe tener un archivo concept/<concepts.slug>/introduction.md. Las reglas de análisis estático para este archivo se especifican a continuación.
  • Cada valor de "concepts" debe tener un archivo concept/<concepts.slug>/links.json. Las reglas de análisis estático para este archivo se especifican a continuación.
  • La clave "key_features" es opcional
  • El valor de "key_features" debe ser un array con una longitud = 6
  • La clave "key_features[].icon" es obligatoria
  • El valor de "key_features[].icon" debe usar uno de los valores de icono predefinidos
  • La clave "key_features[].title" es obligatoria
  • El valor de "key_features[].title" debe ser un string⁴ en Sentence Case con una longitud <= 25
  • La clave "key_features[].content" es obligatoria
  • El valor de "key_features[].content" debe ser un string¹ no vacío con una longitud <= 100
  • La clave "tags" es obligatoria
  • El valor de "tags" debe ser un array de strings
  • Los valores de "tags" no deben tener duplicados
  • Los valores de "tags" deben usar uno de los valores de tag predefinidos

Regla: exercises/concept/<slug>/.meta/config.json es válido

  • El archivo debe ser JSON válido
  • La raíz del JSON debe ser un objeto
  • La clave "blurb" es obligatoria
  • El valor de "blurb" debe ser un string¹ no vacío con una longitud <= 350
  • La clave "source" es opcional
  • El valor de "source" debe ser un string¹ no vacío
  • La clave "source_url" es opcional
  • El valor de "source_url" debe ser una URL
  • La clave "authors" es obligatoria
  • El valor de "authors" debe ser un array no vacío
  • Los valores de "authors" deben ser strings¹ no vacíos
  • Los valores de "authors" no deben tener duplicados
  • Los valores de "authors" se tratan sin distinguir entre mayúsculas y minúsculas
  • La clave "contributors" es opcional
  • El valor de "contributors" debe ser un array
  • Los valores de "contributors" deben ser strings¹ no vacíos
  • Los valores de "contributors" no deben tener duplicados
  • Los valores de "contributors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Los usuarios solo pueden figurar en uno de los dos arrays, "authors" o "contributors" (sin solapamiento)
  • La clave "files.solution" es obligatoria
  • El valor de "files.solution" debe ser un array no vacío
  • Los valores de "files.solution" no deben tener duplicados
  • La clave "files.test" es obligatoria
  • El valor de "files.test" debe ser un array no vacío
  • Los valores de "files.test" no deben tener duplicados
  • La clave "files.exemplar" es obligatoria
  • El valor de "files.exemplar" debe ser un array no vacío
  • Los valores de "files.exemplar" no deben tener duplicados
  • La clave "files.editor" es opcional
  • El valor de "files.editor" debe ser un array
  • Los valores de "files.editor" no deben tener duplicados
  • La clave "files.invalidator" es opcional
  • El valor de "files.invalidator" debe ser un array
  • Los valores de "files.invalidator" no deben tener duplicados
  • Los archivos listados en "files.solution" deben existir
  • Los archivos listados en "files.test" deben existir
  • Los archivos listados en "files.exemplar" deben existir
  • Los archivos listados en "files.editor" deben existir
  • Los archivos listados en "files.invalidator" deben existir
  • Los archivos solo se pueden listar en uno de los arrays "files.solution", "files.test", "files.exemplar" o "files.invalidator" (sin solapamiento)
    • Si el track es d o plsql, los archivos de "files.solution" y "files.test" pueden solaparse
  • La clave "forked_from" es opcional
  • El valor de "forked_from" debe ser un array
  • Los valores de "forked_from" deben ser strings con el formato <track-slug>/<exercise-slug> (p. ej., fsharp/bird-watcher)
  • Los valores de "forked_from" deben referirse a ejercicios realmente implementados
  • Los valores de "forked_from" no deben tener duplicados
  • La clave "language_versions" es opcional
  • El valor de "language_versions" debe ser un string
  • La clave "representer.version" es opcional
  • El valor de "representer.version" debe ser un entero >= 1
  • La clave "icon" es opcional
  • El valor de "icon" debe ser un string² en kebab-case

Regla: exercises/concept/<slug>/.docs/hints.md es válido

  • El Markdown debe cumplir con los estándares de Markdown
  • Todos los encabezados deben ser ## General o ## X. <task>, donde X coincide con el número de tarea del encabezado en instructions.md
  • Todas las pistas deben especificarse como elementos de lista de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: exercises/concept/<slug>/.docs/instructions.md es válido

  • El Markdown debe cumplir con los estándares de Markdown
  • Todas las tareas deben comenzar con un encabezado de nivel dos que empiece con un número seguido de un punto: ## 1. Do X
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: exercises/concept/<slug>/.docs/instructions.md.tpl es válido (si está presente)

Regla: exercises/concept/<slug>/.docs/introduction.md es válido

  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: exercises/practice/<slug>/.meta/config.json es válido

  • El archivo debe ser JSON válido
  • La raíz del JSON debe ser un objeto
  • La clave "blurb" es obligatoria
  • El valor de "blurb" debe ser un string¹ no vacío con una longitud <= 350
  • La clave "source" es opcional
  • El valor de "source" debe ser un string¹ no vacío
  • La clave "source_url" es opcional
  • El valor de "source_url" debe ser una URL
  • La clave "authors" es opcional
  • El valor de "authors" debe ser un array
  • Los valores de "authors" deben ser strings¹ no vacíos
  • Los valores de "authors" no deben tener duplicados
  • Los valores de "authors" se tratan sin distinguir entre mayúsculas y minúsculas
  • La clave "contributors" es opcional
  • El valor de "contributors" debe ser un array
  • Los valores de "contributors" deben ser strings¹ no vacíos
  • Los valores de "contributors" no deben tener duplicados
  • Los valores de "contributors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Los usuarios solo pueden figurar en uno de los dos arrays, "authors" o "contributors" (sin solapamiento)
  • La clave "files.solution" es obligatoria
  • El valor de "files.solution" debe ser un array no vacío
  • Los valores de "files.solution" no deben tener duplicados
  • La clave "files.test" es obligatoria
  • El valor de "files.test" debe ser un array no vacío
  • Los valores de "files.test" no deben tener duplicados
  • La clave "files.example" es obligatoria
  • El valor de "files.example" debe ser un array no vacío
  • Los valores de "files.example" no deben tener duplicados
  • La clave "files.editor" es opcional
  • El valor de "files.editor" debe ser un array
  • Los valores de "files.editor" no deben tener duplicados
  • La clave "files.invalidator" es opcional
  • El valor de "files.invalidator" debe ser un array
  • Los valores de "files.invalidator" no deben tener duplicados
  • Los archivos listados en "files.solution" deben existir
  • Los archivos listados en "files.test" deben existir
  • Los archivos listados en "files.example" deben existir
  • Los archivos listados en "files.editor" deben existir
  • Los archivos listados en "files.invalidator" deben existir
  • Los archivos solo se pueden listar en uno de los arrays "files.solution", "files.test", "files.example o "files.invalidator" (sin solapamiento)
    • Si el track es d o plsql, los archivos de "files.solution" y "files.test" pueden solaparse
  • La clave "language_versions" es opcional
  • El valor de "language_versions" debe ser un string
  • La clave "test_runner" es opcional
  • El valor de "test_runner" debe ser un Boolean
  • La clave "representer.version" es opcional
  • El valor de "representer.version" debe ser un entero >= 1
  • La clave "icon" es opcional
  • El valor de "icon" debe ser un string² en kebab-case

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

  • La presencia del archivo es opcional, salvo que haya un introduction.md o un directorio hermano
  • El archivo debe ser JSON válido
  • La raíz del JSON debe ser un objeto
  • La clave "introduction.authors" es opcional
  • El valor de "introduction.authors" debe ser un array
  • Los valores de "introduction.authors" deben ser strings¹ no vacíos
  • Los valores de "introduction.authors" no deben tener duplicados
  • Los valores de "introduction.authors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Si el array "introduction.authors" no está vacío, debe haber un archivo introduction.md no vacío
  • La clave "introduction.contributors" es opcional
  • El valor de "introduction.contributors" debe ser un array
  • Los valores de "introduction.contributors" deben ser strings¹ no vacíos
  • Los valores de "introduction.contributors" no deben tener duplicados
  • Los valores de "introduction.contributors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Si el array "introduction.contributors" no está vacío, debe haber un archivo introduction.md no vacío
  • Los usuarios solo pueden figurar en uno de los dos arrays, "introduction.authors" o "introduction.contributors" (sin solapamiento)
  • La clave "approaches" es opcional, salvo que haya un directorio hermano presente (que contiene los archivos del enfoque)
  • El valor de "approaches" debe ser un array de objetos
  • La clave "approaches[].uuid" es obligatoria
  • El valor de "approaches[].uuid" debe ser un string⁶ de UUID versión 4 único
  • El valor de "approaches[].uuid" de cada concepto nunca debe cambiar
  • La clave "approaches[].slug" es obligatoria
  • El valor de "approaches[].slug" debe ser un string² en kebab-case con una longitud <= 255
  • El valor de "approaches[].slug" debe tener un archivo <slug>/content.md no vacío correspondiente
  • El valor de "approaches[].slug" debe tener un archivo <slug>/snippet.txt no vacío correspondiente
  • La clave "approaches[].title" es obligatoria
  • El valor de "approaches[].title" debe ser un string³ en Title Case con una longitud <= 255
  • La clave "approaches[].blurb" es obligatoria
  • El valor de "approaches[].blurb" debe ser un string¹ no vacío con una longitud <= 350
  • La clave "approaches[].authors" es obligatoria
  • El valor de "approaches[].authors" debe ser un array no vacío
  • Los valores de "approaches[].authors" deben ser strings¹ no vacíos
  • Los valores de "approaches[].authors" no deben tener duplicados
  • Los valores de "approaches[].authors" se tratan sin distinguir entre mayúsculas y minúsculas
  • La clave "approaches[].contributors" es opcional
  • El valor de "approaches[].contributors" debe ser un array
  • Los valores de "approaches[].contributors" deben ser strings¹ no vacíos
  • Los valores de "approaches[].contributors" no deben tener duplicados
  • Los valores de "approaches[].contributors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Los usuarios solo pueden figurar en uno de los dos arrays, "approaches[].authors" o "approaches[].contributors" (sin solapamiento)
  • La clave "approaches[].tags" es opcional
  • La clave "approaches[].tags.all" es opcional, salvo que "approaches[].tags.any" esté vacío
  • El valor de "approaches[].tags.all" debe ser un array
  • Los valores de "approaches[].tags.all" deben ser tags⁷ no vacíos con una longitud <= 255
  • Los valores de "approaches[].tags.all" no deben tener duplicados
  • La clave "approaches[].tags.any" es opcional, salvo que "approaches[].tags.all" esté vacío
  • El valor de "approaches[].tags.any" debe ser un array
  • Los valores de "approaches[].tags.any" deben ser tags⁷ no vacíos con una longitud <= 255
  • Los valores de "approaches[].tags.any" no deben tener duplicados
  • La clave "approaches[].tags.not" es opcional
  • El valor de "approaches[].tags.not" debe ser un array
  • Los valores de "approaches[].tags.not" deben ser tags⁷ no vacíos con una longitud <= 255
  • Los valores de "approaches[].tags.not" no deben tener duplicados

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

  • La presencia del archivo es obligatoria si existe una entrada "approaches[].slug" que coincida en el archivo .approaches/config.json
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

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

  • La presencia del archivo es obligatoria si existe una entrada "approaches[].slug" que coincida en el archivo .approaches/config.json
  • El snippet debe tener como máximo 8 líneas
  • La extensión del snippet se toma del valor de approaches.snippet_extension en el archivo config.json del track

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

  • La presencia del archivo es opcional, salvo que haya un directorio hermano
  • El archivo debe ser JSON válido
  • La raíz del JSON debe ser un objeto
  • La clave "articles" es opcional, salvo que haya un directorio hermano presente (que contiene los archivos del artículo)
  • El valor de "articles" debe ser un array de objetos
  • La clave "articles[].uuid" es obligatoria
  • El valor de "articles[].uuid" debe ser un string⁶ de UUID versión 4 único
  • El valor de "articles[].uuid" de cada concepto nunca debe cambiar
  • La clave "articles[].slug" es obligatoria
  • El valor de "articles[].slug" debe ser un string² en kebab-case con una longitud <= 255
  • El valor de "articles[].slug" debe tener un archivo <slug>/content.md no vacío correspondiente
  • El valor de "articles[].slug" debe tener un archivo <slug>/snippet.md no vacío correspondiente
  • La clave "articles[].title" es obligatoria
  • El valor de "articles[].title" debe ser un string³ en Title Case con una longitud <= 255
  • La clave "articles[].blurb" es obligatoria
  • El valor de "articles[].blurb" debe ser un string¹ no vacío con una longitud <= 350
  • La clave "articles[].authors" es obligatoria
  • El valor de "articles[].authors" debe ser un array no vacío
  • Los valores de "articles[].authors" deben ser strings¹ no vacíos
  • Los valores de "articles[].authors" no deben tener duplicados
  • Los valores de "articles[].authors" se tratan sin distinguir entre mayúsculas y minúsculas
  • La clave "articles[].contributors" es opcional
  • El valor de "articles[].contributors" debe ser un array
  • Los valores de "articles[].contributors" deben ser strings¹ no vacíos
  • Los valores de "articles[].contributors" no deben tener duplicados
  • Los valores de "articles[].contributors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Los usuarios solo pueden figurar en uno de los dos arrays, "articles[].authors" o "articles[].contributors" (sin solapamiento)

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

  • La presencia del archivo es obligatoria si existe una entrada "articles[].slug" que coincida en el archivo .articles/config.json
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

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

  • La presencia del archivo es obligatoria si existe una entrada "articles[].slug" que coincida en el archivo .articles/config.json
  • El Markdown debe cumplir con los estándares de Markdown
  • El snippet debe tener como máximo 8 líneas (los marcadores de cerca de código al inicio y al final se ignoran)

Regla: exercises/shared/.docs/debug.md es válido

  • La presencia del archivo es opcional
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: exercises/shared/.docs/help.md es válido

  • La presencia del archivo es obligatoria
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: exercises/shared/.docs/tests.md es válido

  • La presencia del archivo es obligatoria
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: concepts/<slug>/about.md es válido

  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: concepts/<slug>/introduction.md es válido

  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)
  • El archivo debe ser JSON válido
  • La raíz del JSON debe ser un array
  • La propiedad "[].url" es obligatoria
  • El valor de "[].url" debe ser una URL
  • La propiedad "[].description" es obligatoria
  • El valor de "[].description" debe ser un string¹ no vacío
  • La propiedad "[].icon_url" es opcional
  • El valor de "[].icon_url" debe ser una URL

Regla: concept/<slug>/.meta/config.json es válido

  • El archivo debe ser JSON válido
  • La raíz del JSON debe ser un objeto
  • La clave "blurb" es obligatoria
  • El valor de "blurb" debe ser un string¹ no vacío con una longitud <= 350
  • La clave "authors" es obligatoria
  • El valor de "authors" debe ser un array
  • Los valores de "authors" deben ser strings¹ no vacíos
  • Los valores de "authors" no deben tener duplicados
  • Los valores de "authors" se tratan sin distinguir entre mayúsculas y minúsculas
  • La clave "contributors" es opcional
  • El valor de "contributors" debe ser un array
  • Los valores de "contributors" deben ser strings¹ no vacíos
  • Los valores de "contributors" no deben tener duplicados
  • Los valores de "contributors" se tratan sin distinguir entre mayúsculas y minúsculas
  • Los usuarios solo pueden figurar en uno de los dos arrays, "authors" o "contributors" (sin solapamiento)

Regla: docs/ABOUT.md es válido

  • La presencia del archivo es obligatoria
  • El contenido del archivo no debe estar vacío
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: docs/INSTALLATION.md es válido

  • La presencia del archivo es obligatoria
  • El contenido del archivo no debe estar vacío
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: docs/LEARNING.md es válido

  • La presencia del archivo es obligatoria
  • El contenido del archivo no debe estar vacío
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: docs/RESOURCES.md es válido

  • La presencia del archivo es obligatoria
  • El contenido del archivo no debe estar vacío
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Regla: docs/SNIPPET.txt es válido

  • La presencia del archivo es obligatoria
  • El contenido del archivo no debe estar vacío

Regla: docs/TESTS.md es válido

  • La presencia del archivo es obligatoria
  • El contenido del archivo no debe estar vacío
  • El Markdown debe cumplir con los estándares de Markdown
  • Los enlaces deben ser absolutos (no se permiten enlaces relativos)

Glosario

  1. String no vacío: un string que contiene al menos un carácter que no sea un espacio en blanco.

  2. String en kebab-case: un string que solo contiene caracteres del rango [a-z0-9], separados opcionalmente por guiones (p. ej., «two-fer»). Debe coincidir con la expresión regular: ^[a-z0-9]+(-[a-z0-9]+)*$

  3. String en Title Case: un string no vacío que sigue las siguientes pautas del Manual de Estilo de Chicago:

    • Se escriben en mayúscula la primera y la última palabra de títulos y subtítulos.
    • Se escriben en mayúscula las palabras «importantes» (sustantivos, pronombres, verbos, adjetivos, adverbios y algunas conjunciones).
    • Se escriben en minúscula las conjunciones and, but, for, or y nor.
    • Se escriben en minúscula los artículos the, a y an.
    • Se escriben en minúscula las preposiciones, sin importar su longitud, salvo cuando son tónicas, se usan de forma adverbial o adjetival, o se usan como conjunciones.
    • Se escriben en minúscula las palabras to y as.
    • Se escribe en minúscula la segunda parte de los nombres de especies en latín.
  4. String en Sentence Case: un string no vacío que sigue las siguientes pautas:

    • Se escribe en mayúscula la primera palabra de la oración, así como los nombres propios y otras palabras según lo exija una regla más específica.
  5. Patrón de files válido: un string¹ no vacío que especifica la ubicación de un archivo usado en un ejercicio, relativa al directorio del ejercicio. Un patrón puede usar uno de los siguientes marcadores de posición:

    • %{kebab_slug}: el slug del ejercicio en kebab-case (p. ej., bit-manipulation)
    • %{snake_slug}: el slug del ejercicio en snake_case (p. ej., bit_manipulation)
    • %{camel_slug}: el slug del ejercicio en camelCase (p. ej., bitManipulation)
    • %{pascal_slug}: el slug del ejercicio en PascalCase (p. ej., BitManipulation)
  6. String de UUID versión 4 único: un string que cumple todas estas condiciones:

    • Solo existe una vez en el archivo config.json de nivel de track de un track de Exercism dado
    • No existe en el archivo config.json de nivel de track de ningún otro track de Exercism
    • No existe en ningún archivo canonical-data.json de https://github.com/exercism/problem-specifications
    • No existe en ningún otro lugar de Exercism
    • Coincide con la expresión regular:
    ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    

    Por ejemplo, el siguiente UUID tiene la forma correcta:

    d334ffe3-657e-4725-a950-290b284b6d9f
    

    Puedes ejecutar configlet uuid para generar un UUID adecuado.

  7. tag de analyzer válido: un string¹ no vacío con el formato <category>:<thing>. El valor de <category> debe ser uno de los siguientes:

  • paradigm (p. ej., paradigm:functional)
  • technique (p. ej., technique:recursion)
  • construct (p. ej., construct:bitwise-and)
  • uses (p. ej., uses:DateTime.add_seconds)

El valor de <thing> debe ser un string¹ no vacío.