configlet lint


configlet的主要用途是代码检查:检查某个 track 的配置文件结构是否正确,既要语法正确,也要语义正确。配置有误的 track 可能无法正确同步,可能在网站上显示异常,也可能给用户带来欠佳的体验,因此 configlet 的这些把关检查对维护 Exercism 的完整性起着重要作用。

用法

可以用 lint 命令对某个 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]

规则

以下就是 configlet 会检查的各项规则。

规则:必需文件均已存在

代码检查器应检查所有必需文件是否都已存在。必须存在的非练习专属文件有:

  • 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

必须存在的概念练习专属文件有:

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

实践练习也会有类似的清单,但我们还没有定义相应的规范。

config.json 中列出的每个概念都应有以下文件:

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

规则:config.json 文件有效

config.json 文件需要满足以下检查:

  • 文件必须是有效的 JSON
  • "language"键是必需的
  • "language"的值必须是长度 <= 255 的非空白字符串¹
  • "slug"键是必需的
  • "slug"的值必须是长度 <= 255 的 kebab-case 字符串²
  • "active"键是必需的
  • "active"的值必须是布尔值
  • "blurb"键是必需的
  • "blurb"的值必须是长度 <= 400 的非空白字符串¹
  • "version"键是必需的
  • "version"的值必须是整数 3
  • "status.concept_exercises"键是必需的
  • "status.concept_exercises"的值必须是布尔值
  • "status.test_runner"键是必需的
  • "status.test_runner"的值必须是布尔值
  • "status.representer"键是必需的
  • "status.representer"的值必须是布尔值
  • "status.analyzer"键是必需的
  • "status.analyzer"的值必须是布尔值
  • "online_editor.indent_style"键是必需的
  • "online_editor.indent_style"的值必须是字符串 space 或 tab
  • "online_editor.indent_size"键是必需的
  • "online_editor.indent_size"的值必须是 >= 0 且 <= 8 的整数
  • "online_editor.highlightjs_language"键是可选的
  • "online_editor.highlightjs_language"的值必须是非空白字符串¹
  • "files"键是可选的
  • "files"的值必须是对象
  • "files.solution"键是可选的
  • "files.solution"的值必须是数组
  • "files.solution"的值必须是有效模式⁵
  • "files.solution"的值不能重复
  • "files.test"键是可选的
  • "files.test"的值必须是数组
  • "files.test"的值必须是有效模式⁵
  • "files.test"的值不能重复
  • "files.example"键是可选的
  • "files.example"的值必须是数组
  • "files.example"的值必须是有效模式⁵
  • "files.example"的值不能重复
  • "files.exemplar"键是可选的
  • "files.exemplar"的值必须是数组
  • "files.exemplar"的值必须是有效模式⁵
  • "files.exemplar"的值不能重复
  • "files.editor"键是可选的
  • "files.editor"的值必须是数组
  • "files.editor"的值必须是有效模式⁵
  • "files.editor"的值不能重复
  • "files.invalidator"键是可选的
  • "files.invalidator"的值必须是数组
  • "files.invalidator"的值必须是有效模式⁵
  • "files.invalidator"的值不能重复
  • 模式只能出现在 "files.solution"、"files.test"、"files.example"、"files.exemplar"、"files.editor" 或 "files.invalidator" 数组中的一个里(不能重叠)
    • 如果 track 是 d 或 plsql,"files.solution" 和 "files.test" 文件_可以_重叠
    • "files.example 和 "files.exemplar" 文件_可以_重叠
  • 如果 "status.test_runner" 等于 true,则 "test_runner.average_run_time"键是必需的
  • "test_runner.average_run_time"的值必须是 > 0 的整数
  • 如果 track 有一个或多个思路,则 "approaches.snippet_extension"键是必需的
  • "approaches.snippet_extension"的值必须是非空白字符串¹
  • "exercises"键是必需的
  • "exercises.concept"键是必需的
  • "exercises.concept"的值必须是数组
  • "exercises.concept[].slug"键是必需的
  • "exercises.concept[].slug"的值必须是长度 <= 255 的 kebab-case 字符串²
  • "exercises.concept[].slug"的值在 "exercises.concept[].slug" 中必须唯一,且不能出现在 "exercises.practice[].slug" 中
  • "exercises.concept[].name"键是必需的
  • "exercises.concept[].name"的值必须是长度 <= 255 的标题式大写字符串³
  • "exercises.concept[].uuid"键是必需的
  • "exercises.concept[].uuid"的值必须是唯一的版本 4 UUID 字符串⁶
  • 每个练习的 "exercises.concept[].uuid" 值都绝不能改变
  • "exercises.concept[].concepts"键是必需的
  • 如果 "exercises.concept[].status" 不等于 deprecated,则 "exercises.concept[].concepts"的值必须是由字符串组成的非空数组
  • 如果 "exercises.concept[].status" 等于 deprecated,则 "exercises.concept[].concepts"的值必须是空数组
  • "exercises.concept[].concepts"的值必须是 kebab-case 字符串²
  • "exercises.concept[].concepts"的值不能重复
  • "exercises.concept[].concepts"的值不能出现在其他任何概念练习的 "concepts" 属性中
  • "exercises.concept[].concepts"的值必须与其中某个概念的 "concepts.slug" 属性匹配
  • "exercises.concept[].prerequisites"键是必需的
  • 如果 "exercises.concept[].status" 不等于 deprecated,则 "exercises.concept[].prerequisites"的值必须是由字符串组成的非空数组,不过恰好有一个练习_可以_以空数组作为它的值
  • 如果 "exercises.concept[].status" 等于 deprecated,则 "exercises.concept[].prerequisites"的值必须是空数组
  • "exercises.concept[].prerequisites"的值必须是 kebab-case 字符串²
  • "exercises.concept[].prerequisites"的值不能重复
  • "exercises.concept[].prerequisites"的值必须与任何其他概念练习的 "concepts" 属性值匹配
  • "exercises.concept[].prerequisites"的值不能与该练习 "exercises.concept[].concepts" 属性中的任何值相同
  • "exercises.concept[].prerequisites"的值必须与其中某个概念的 "concepts.slug" 属性匹配
  • "exercises.concept[].concepts" 和 "exercises.concept[].prerequisites" 之间不能存在任何环路
  • "exercises.concept[].status"键是可选的
  • "exercises.concept[].status"的值必须是字符串 wip、beta、active 或 deprecated
  • "exercises.practice"键是必需的
  • "exercises.practice"的值必须是数组
  • "exercises.practice[].slug"键是必需的
  • "exercises.practice[].slug"的值必须是长度 <= 255 的 kebab-case 字符串²
  • "exercises.practice[].slug"的值在 "exercises.practice[].slug" 中必须唯一,且不能出现在 "exercises.concept[].slug" 中
  • 必须恰好有一个 "exercises.practice[].slug" 的值是字符串 hello-world
  • "exercises.practice[].name"键是必需的
  • "exercises.practice[].name"的值必须是长度 <= 255 的标题式大写字符串³
  • "exercises.practice[].uuid"键是必需的
  • "exercises.practice[].uuid"的值必须是唯一的版本 4 UUID 字符串⁶
  • 每个练习的 "exercises.practice[].uuid" 值都绝不能改变
  • "exercises.practice[].difficulty"键是必需的
  • "exercises.practice[].difficulty"的值必须是 >= 1 且 <= 10 的整数
  • "exercises.practice[].practices"键是必需的
  • 如果 "exercises.practice[].status" 不等于 deprecated,则 "exercises.practice[].practices"的值必须是由字符串组成的非空数组
  • 如果 "exercises.practice[].status" 等于 deprecated,则 "exercises.practice[].practices"的值必须是空数组
  • "exercises.practice[].practices"的值必须是 kebab-case 字符串²
  • "exercises.practice[].practices"的值不能重复
  • "exercises.practice[].practices"的值必须与其中某个概念的 "concepts[].slug" 属性匹配
  • "exercises.practice[].practices"的值在全部练习中最多只能引用某个概念的 slug 10 次
  • "exercises.practice[].prerequisites"键是必需的
  • 如果 "exercises.practice[].status" 不等于 deprecated,则 "exercises.practice[].prerequisites"的值必须是由字符串组成的非空数组
  • 如果 "exercises.practice[].status" 等于 deprecated,则 "exercises.practice[].prerequisites"的值必须是空数组
  • 如果 "exercises.practice[].slug" 等于 hello-world,则 "exercises.practice[].prerequisites"的值必须是空数组
  • "exercises.practice[].prerequisites"的值必须是 kebab-case 字符串²
  • "exercises.practice[].prerequisites"的值不能重复
  • "exercises.practice[].prerequisites"的值必须与任何概念练习的 "exercises.concept[].concepts" 值匹配
  • "exercises.practice[].prerequisites"的值必须与其中某个概念的 "concepts[].slug" 属性匹配
  • "exercises.practice[].status"键是可选的
  • "exercises.practice[].status"的值必须是字符串 wip、beta、active 或 deprecated
  • 如果 "exercises.practice[].slug" 等于 hello-world,则 "exercises.practice[].status"的值必须省略,或者必须是字符串 active
  • "exercises.foregone"键是可选的
  • "exercises.foregone"的值必须是数组
  • "exercises.foregone"的值必须是 kebab-case 字符串²
  • "exercises.foregone"的值不能重复
  • "exercises.foregone"的值不能与任何概念练习或实践练习的 slug 相同
  • "concepts"键是必需的
  • "concepts"的值必须是数组
  • "concepts[].uuid"键是必需的
  • "concepts[].uuid"的值必须是唯一的版本 4 UUID 字符串⁶
  • 每个概念的 "concepts[].uuid" 值都绝不能改变
  • "concepts[].slug"键是必需的
  • "concepts[].slug"的值必须是长度 <= 255 的 kebab-case 字符串²
  • "concepts[].name"键是必需的
  • "concepts[].name"的值必须是长度 <= 255 的标题式大写字符串³
  • "concepts[].tags"键是可选的
  • "concepts[].tags.all"键是可选的,除非 "concepts[].tags.any" 为空
  • "concepts[].tags.all"的值必须是数组
  • "concepts[].tags.all"的值必须是长度 <= 255 的非空白 tag⁷ 字符串
  • "concepts[].tags.all"的值不能重复
  • "concepts[].tags.any"键是可选的,除非 "concepts[].tags.all" 为空
  • "concepts[].tags.any"的值必须是数组
  • "concepts[].tags.any"的值必须是长度 <= 255 的非空白 tag⁷ 字符串
  • "concepts[].tags.any"的值不能重复
  • "concepts[].tags.not"键是可选的
  • "concepts[].tags.not"的值必须是数组
  • "concepts[].tags.not"的值必须是长度 <= 255 的非空白 tag⁷ 字符串
  • "concepts[].tags.not"的值不能重复
  • 每个 "concepts" 值都必须有 concept/<concepts.slug>/about.md 文件。该文件的检查规则在下面说明。
  • 每个 "concepts" 值都必须有 concept/<concepts.slug>/introduction.md 文件。该文件的检查规则在下面说明。
  • 每个 "concepts" 值都必须有 concept/<concepts.slug>/links.json 文件。该文件的检查规则在下面说明。
  • "key_features"键是可选的
  • "key_features"的值必须是长度为 6 的数组
  • "key_features[].icon"键是必需的
  • "key_features[].icon"的值必须使用某个预定义的图标值
  • "key_features[].title"键是必需的
  • "key_features[].title"的值必须是长度 <= 25 的句首大写字符串⁴
  • "key_features[].content"键是必需的
  • "key_features[].content"的值必须是长度 <= 100 的非空白字符串¹
  • "tags"键是必需的
  • "tags"的值必须是字符串数组
  • "tags"的值不能重复
  • "tags"的值必须使用某个预定义的 tag 值

规则:exercises/concept/<slug>/.meta/config.json 有效

  • 文件必须是有效的 JSON
  • JSON 根节点必须是对象
  • "blurb"键是必需的
  • "blurb"的值必须是长度 <= 350 的非空白字符串¹
  • "source"键是可选的
  • "source"的值必须是非空白字符串¹
  • "source_url"键是可选的
  • "source_url"的值必须是 URL
  • "authors"键是必需的
  • "authors"的值必须是非空数组
  • "authors"的值必须是非空白字符串¹
  • "authors"的值不能重复
  • "authors"的值按不区分大小写处理
  • "contributors"键是可选的
  • "contributors"的值必须是数组
  • "contributors"的值必须是非空白字符串¹
  • "contributors"的值不能重复
  • "contributors"的值按不区分大小写处理
  • 用户只能出现在 "authors" 或 "contributors" 数组中的一个里(不能重叠)
  • "files.solution"键是必需的
  • "files.solution"的值必须是非空数组
  • "files.solution"的值不能重复
  • "files.test"键是必需的
  • "files.test"的值必须是非空数组
  • "files.test"的值不能重复
  • "files.exemplar"键是必需的
  • "files.exemplar"的值必须是非空数组
  • "files.exemplar"的值不能重复
  • "files.editor"键是可选的
  • "files.editor"的值必须是数组
  • "files.editor"的值不能重复
  • "files.invalidator"键是可选的
  • "files.invalidator"的值必须是数组
  • "files.invalidator"的值不能重复
  • "files.solution" 中列出的文件必须存在
  • "files.test" 中列出的文件必须存在
  • "files.exemplar" 中列出的文件必须存在
  • "files.editor" 中列出的文件必须存在
  • "files.invalidator" 中列出的文件必须存在
  • 文件只能出现在 "files.solution"、"files.test"、"files.exemplar" 或 "files.invalidator" 数组中的一个里(不能重叠)
    • 如果 track 是 d 或 plsql,"files.solution" 和 "files.test" 文件_可以_重叠
  • "forked_from"键是可选的
  • "forked_from"的值必须是数组
  • "forked_from"的值必须是格式为 <track-slug>/<exercise-slug> 的字符串(例如 fsharp/bird-watcher)
  • "forked_from"的值必须指向实际已实现的练习
  • "forked_from"的值不能重复
  • "language_versions"键是可选的
  • "language_versions"的值必须是字符串
  • "representer.version"键是可选的
  • "representer.version"的值必须是 >= 1 的整数
  • "icon"键是可选的
  • "icon"的值必须是 kebab-case 字符串²

规则:exercises/concept/<slug>/.docs/hints.md 有效

  • Markdown 必须符合 Markdown 标准
  • 所有标题都必须是 ## General 或 ## X. <task>,其中 X 与 instructions.md 中的任务编号标题一致
  • 所有提示都必须写成 Markdown 列表项
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/concept/<slug>/.docs/instructions.md 有效

  • Markdown 必须符合 Markdown 标准
  • 所有任务都必须以二级标题开头,标题以数字加一个点开头:## 1. Do X
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/concept/<slug>/.docs/instructions.md.tpl 有效(如果存在)

  • 每个概念占位符中的概念都必须与 track 的 config.json 中某个概念的 "concepts.slug" 属性匹配。

规则:exercises/concept/<slug>/.docs/introduction.md 有效

  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/practice/<slug>/.meta/config.json 有效

  • 文件必须是有效的 JSON
  • JSON 根节点必须是对象
  • "blurb"键是必需的
  • "blurb"的值必须是长度 <= 350 的非空白字符串¹
  • "source"键是可选的
  • "source"的值必须是非空白字符串¹
  • "source_url"键是可选的
  • "source_url"的值必须是 URL
  • "authors"键是可选的
  • "authors"的值必须是数组
  • "authors"的值必须是非空白字符串¹
  • "authors"的值不能重复
  • "authors"的值按不区分大小写处理
  • "contributors"键是可选的
  • "contributors"的值必须是数组
  • "contributors"的值必须是非空白字符串¹
  • "contributors"的值不能重复
  • "contributors"的值按不区分大小写处理
  • 用户只能出现在 "authors" 或 "contributors" 数组中的一个里(不能重叠)
  • "files.solution"键是必需的
  • "files.solution"的值必须是非空数组
  • "files.solution"的值不能重复
  • "files.test"键是必需的
  • "files.test"的值必须是非空数组
  • "files.test"的值不能重复
  • "files.example"键是必需的
  • "files.example"的值必须是非空数组
  • "files.example"的值不能重复
  • "files.editor"键是可选的
  • "files.editor"的值必须是数组
  • "files.editor"的值不能重复
  • "files.invalidator"键是可选的
  • "files.invalidator"的值必须是数组
  • "files.invalidator"的值不能重复
  • "files.solution" 中列出的文件必须存在
  • "files.test" 中列出的文件必须存在
  • "files.example" 中列出的文件必须存在
  • "files.editor" 中列出的文件必须存在
  • "files.invalidator" 中列出的文件必须存在
  • 文件只能出现在 "files.solution"、"files.test"、"files.example 或 "files.invalidator" 数组中的一个里(不能重叠)
    • 如果 track 是 d 或 plsql,"files.solution" 和 "files.test" 文件_可以_重叠
  • "language_versions"键是可选的
  • "language_versions"的值必须是字符串
  • "test_runner"键是可选的
  • "test_runner"的值必须是布尔值
  • "representer.version"键是可选的
  • "representer.version"的值必须是 >= 1 的整数
  • "icon"键是可选的
  • "icon"的值必须是 kebab-case 字符串²

规则:exercises/{concept|practice}/<slug>/.approaches/config.json 有效

  • 文件是可选的,除非存在 introduction.md 或同级目录
  • 文件必须是有效的 JSON
  • JSON 根节点必须是对象
  • "introduction.authors"键是可选的
  • "introduction.authors"的值必须是数组
  • "introduction.authors"的值必须是非空白字符串¹
  • "introduction.authors"的值不能重复
  • "introduction.authors"的值按不区分大小写处理
  • 如果 "introduction.authors" 数组非空,则必须有非空的 introduction.md 文件
  • "introduction.contributors"键是可选的
  • "introduction.contributors"的值必须是数组
  • "introduction.contributors"的值必须是非空白字符串¹
  • "introduction.contributors"的值不能重复
  • "introduction.contributors"的值按不区分大小写处理
  • 如果 "introduction.contributors" 数组非空,则必须有非空的 introduction.md 文件
  • 用户只能出现在 "introduction.authors" 或 "introduction.contributors" 数组中的一个里(不能重叠)
  • "approaches"键是可选的,除非存在同级目录(里面存放的是各个思路的文件)
  • "approaches"的值必须是对象数组
  • "approaches[].uuid"键是必需的
  • "approaches[].uuid"的值必须是唯一的版本 4 UUID 字符串⁶
  • 每个概念的 "approaches[].uuid" 值都绝不能改变
  • "approaches[].slug"键是必需的
  • "approaches[].slug"的值必须是长度 <= 255 的 kebab-case 字符串²
  • "approaches[].slug"的值必须有对应的非空 <slug>/content.md 文件
  • "approaches[].slug"的值必须有对应的非空 <slug>/snippet.txt 文件
  • "approaches[].title"键是必需的
  • "approaches[].title"的值必须是长度 <= 255 的标题式大写字符串³
  • "approaches[].blurb"键是必需的
  • "approaches[].blurb"的值必须是长度 <= 350 的非空白字符串¹
  • "approaches[].authors"键是必需的
  • "approaches[].authors"的值必须是非空数组
  • "approaches[].authors"的值必须是非空白字符串¹
  • "approaches[].authors"的值不能重复
  • "approaches[].authors"的值按不区分大小写处理
  • "approaches[].contributors"键是可选的
  • "approaches[].contributors"的值必须是数组
  • "approaches[].contributors"的值必须是非空白字符串¹
  • "approaches[].contributors"的值不能重复
  • "approaches[].contributors"的值按不区分大小写处理
  • 用户只能出现在 "approaches[].authors" 或 "approaches[].contributors" 数组中的一个里(不能重叠)
  • "approaches[].tags"键是可选的
  • "approaches[].tags.all"键是可选的,除非 "approaches[].tags.any" 为空
  • "approaches[].tags.all"的值必须是数组
  • "approaches[].tags.all"的值必须是长度 <= 255 的非空白 tag⁷ 字符串
  • "approaches[].tags.all"的值不能重复
  • "approaches[].tags.any"键是可选的,除非 "approaches[].tags.all" 为空
  • "approaches[].tags.any"的值必须是数组
  • "approaches[].tags.any"的值必须是长度 <= 255 的非空白 tag⁷ 字符串
  • "approaches[].tags.any"的值不能重复
  • "approaches[].tags.not"键是可选的
  • "approaches[].tags.not"的值必须是数组
  • "approaches[].tags.not"的值必须是长度 <= 255 的非空白 tag⁷ 字符串
  • "approaches[].tags.not"的值不能重复

规则:exercises/{concept|practice}/<slug>/.approaches/<approach-slug>/content.md 有效

  • 如果 .approaches/config.json 文件中存在匹配的 "approaches[].slug" 条目,则该文件是必需的
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/{concept|practice}/<slug>/.approaches/<approach-slug>/snippet.<snippet-extension> 有效

  • 如果 .approaches/config.json 文件中存在匹配的 "approaches[].slug" 条目,则该文件是必需的
  • 代码片段最多只能有 8 行
  • 代码片段的扩展名取自 track 的 config.json 文件中的 approaches.snippet_extension 值

规则:exercises/{concept|practice}/<slug>/.articles/config.json 有效

  • 文件是可选的,除非存在同级目录
  • 文件必须是有效的 JSON
  • JSON 根节点必须是对象
  • "articles"键是可选的,除非存在同级目录(里面存放的是各篇文章的文件)
  • "articles"的值必须是对象数组
  • "articles[].uuid"键是必需的
  • "articles[].uuid"的值必须是唯一的版本 4 UUID 字符串⁶
  • 每个概念的 "articles[].uuid" 值都绝不能改变
  • "articles[].slug"键是必需的
  • "articles[].slug"的值必须是长度 <= 255 的 kebab-case 字符串²
  • "articles[].slug"的值必须有对应的非空 <slug>/content.md 文件
  • "articles[].slug"的值必须有对应的非空 <slug>/snippet.md 文件
  • "articles[].title"键是必需的
  • "articles[].title"的值必须是长度 <= 255 的标题式大写字符串³
  • "articles[].blurb"键是必需的
  • "articles[].blurb"的值必须是长度 <= 350 的非空白字符串¹
  • "articles[].authors"键是必需的
  • "articles[].authors"的值必须是非空数组
  • "articles[].authors"的值必须是非空白字符串¹
  • "articles[].authors"的值不能重复
  • "articles[].authors"的值按不区分大小写处理
  • "articles[].contributors"键是可选的
  • "articles[].contributors"的值必须是数组
  • "articles[].contributors"的值必须是非空白字符串¹
  • "articles[].contributors"的值不能重复
  • "articles[].contributors"的值按不区分大小写处理
  • 用户只能出现在 "articles[].authors" 或 "articles[].contributors" 数组中的一个里(不能重叠)

规则:exercises/{concept|practice}/<slug>/.articles/<article-slug>/content.md 有效

  • 如果 .articles/config.json 文件中存在匹配的 "articles[].slug" 条目,则该文件是必需的
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/{concept|practice}/<slug>/.articles/<article-slug>/snippet.md 有效

  • 如果 .articles/config.json 文件中存在匹配的 "articles[].slug" 条目,则该文件是必需的
  • Markdown 必须符合 Markdown 标准
  • 代码片段最多只能有 8 行(开头和结尾的代码围栏标记不计入)

规则:exercises/shared/.docs/debug.md 有效

  • 文件是可选的
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/shared/.docs/help.md 有效

  • 文件是必需的
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:exercises/shared/.docs/tests.md 有效

  • 文件是必需的
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:concepts/<slug>/about.md 有效

  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:concepts/<slug>/introduction.md 有效

  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)
  • 文件必须是有效的 JSON
  • JSON 根节点必须是数组
  • "[].url"属性是必需的
  • "[].url"的值必须是 URL
  • "[].description"属性是必需的
  • "[].description"的值必须是非空白字符串¹
  • "[].icon_url"属性是可选的
  • "[].icon_url"的值必须是 URL

规则:concept/<slug>/.meta/config.json 有效

  • 文件必须是有效的 JSON
  • JSON 根节点必须是对象
  • "blurb"键是必需的
  • "blurb"的值必须是长度 <= 350 的非空白字符串¹
  • "authors"键是必需的
  • "authors"的值必须是数组
  • "authors"的值必须是非空白字符串¹
  • "authors"的值不能重复
  • "authors"的值按不区分大小写处理
  • "contributors"键是可选的
  • "contributors"的值必须是数组
  • "contributors"的值必须是非空白字符串¹
  • "contributors"的值不能重复
  • "contributors"的值按不区分大小写处理
  • 用户只能出现在 "authors" 或 "contributors" 数组中的一个里(不能重叠)

规则:docs/ABOUT.md 有效

  • 文件是必需的
  • 文件内容不能为空白
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:docs/INSTALLATION.md 有效

  • 文件是必需的
  • 文件内容不能为空白
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:docs/LEARNING.md 有效

  • 文件是必需的
  • 文件内容不能为空白
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:docs/RESOURCES.md 有效

  • 文件是必需的
  • 文件内容不能为空白
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

规则:docs/SNIPPET.txt 有效

  • 文件是必需的
  • 文件内容不能为空白

规则:docs/TESTS.md 有效

  • 文件是必需的
  • 文件内容不能为空白
  • Markdown 必须符合 Markdown 标准
  • 链接必须是绝对链接(不允许相对链接)

术语表

  1. 非空白字符串:至少包含一个非空白字符的字符串。

  2. kebab-case 字符串:只包含 [a-z0-9] 范围内的字符、可选地用短横线分隔的字符串(例如 “two-fer”)。它必须匹配正则表达式:^[a-z0-9]+(-[a-z0-9]+)*$

  3. 标题式大写字符串:遵循下面这些《芝加哥手册》中的指南的非空白字符串:

    • 标题和副标题的第一个和最后一个单词首字母大写。
    • 把“主要”单词(名词、代词、动词、形容词、副词以及部分连词)首字母大写。
    • 连词 and、but、for、or 和 nor 小写。
    • 冠词 the、a 和 an 小写。
    • 介词一律小写,不论长短,但介词受到强调、用作副词或形容词,或者用作连词时除外。
    • 单词 to 和 as 小写。
    • 拉丁学名中的第二部分小写。
  4. 句首大写字符串:遵循下面这些指南的非空白字符串:

    • 句子第一个单词首字母大写,专有名词以及更具体的规则要求大写的其他单词也同样首字母大写。
  5. 有效的 files 模式:一个非空白字符串¹,用来指定练习中某个文件相对于练习目录的位置。模式可以使用以下占位符之一:

    • %{kebab_slug}:kebab-case 形式的练习 slug(例如 bit-manipulation)
    • %{snake_slug}:snake_case 形式的练习 slug(例如 bit_manipulation)
    • %{camel_slug}:camelCase 形式的练习 slug(例如 bitManipulation)
    • %{pascal_slug}:PascalCase 形式的练习 slug(例如 BitManipulation)
  6. 唯一的版本 4 UUID 字符串:满足以下所有条件的字符串:

    • 在某个 Exercism track 的 track 级 config.json 文件中只出现一次
    • 不出现在其他任何 Exercism track 的 track 级 config.json 文件中
    • 不出现在 https://github.com/exercism/problem-specifications 里的任何 canonical-data.json 文件中
    • 不出现在 Exercism 的其他任何地方
    • 匹配以下正则表达式:
    ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    

    例如,下面这个 UUID 格式正确:

    d334ffe3-657e-4725-a950-290b284b6d9f
    

    你可以运行 configlet uuid 生成一个合适的 UUID。

  7. 有效的分析器 tag:格式为 <category>:<thing> 的非空白字符串¹。 <category>的值必须是以下之一:

  • paradigm(例如 paradigm:functional)
  • technique(例如 technique:recursion)
  • construct(例如 construct:bitwise-and)
  • uses(例如 uses:DateTime.add_seconds)

<thing>的值必须是非空白字符串¹。