关于 conformetry-configure
用于配置 conformetry 生成器并编写模板的技能,说明输入、钩子、实例匹配、占位符和一致性阈值在命令行宿主与 Nx 插件中的行为。
主要功能
- 01生成器配置与校验
- 02实例组与路径匹配
- 03JSON Schema 输入设置
- 04生成钩子与文件系统规则
- 05Mustache 占位符与推断
- 06一致性阈值指南
适用场景
- 01为工作区模板定义生成器
- 02将实例限定到 Nx 项目或 glob
- 03在模板生成前后添加钩子
- 04排查占位符与一致性问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ organizzolini/ codebase --skill conformetry-configure安装后在 Claude Code 中输入/conformetry-configure确认已加载。
附带文件references/languages.md
详细介绍
配置 conformetry 并编写模板
生成器将一个名称与一个模板配对——一个普通文件夹,里面是普通文件——以及渲染模板所需的输入。配置声明生成器;模板文件夹则完整定义了要生成的内容。后续也会以同一个模板为基准来衡量实例,因此模板既是起点,也是标准。
配置
配置文件默认导出一个数组,每个生成器对应一个条目。只有两个必填字段:
| 字段 | 必填 | 含义 |
|---|---|---|
name | 是 | 调用生成器时使用的名称 |
templatePath | 是 | 相对于工作区根目录的模板文件夹 |
inputs | 否 | 模板渲染时使用的值,以 JSON Schema 片段表示 |
instances | 否 | 此生成器的输出已有的存放位置 |
description | 否 | 列出生成器时显示 |
hooks | 否 | 在生成前后运行的函数;参见 Hooks |
threshold | 否 | 此生成器的实例允许达到的最低符合度评分,范围为 0 到 1 |
不接受未知键,因此拼错字段,或使用已被彻底移除的 aliases,都会导致加载失败,而不是悄无声息地不起作用。可通过列出生成器来确认条目是否生效。每条 conformetry 命令都必须使用 --config <path>——没有默认配置文件:
conformetry templates --config configuration/conformetry.config.ts
未指定路径时,命令会失败,并抛出 ConfigurationPathRequiredError,指出未设置的标志或选项。在 Nx 中,这指的是 nx.json 里 @conformetry/nx 插件的 configurationPath 选项,或执行器和 sync 生成器的 configuration 选项。
没有 inputs 和 instances 的生成器也是合法的:它会渲染固定模板,后续不会对任何内容进行验证。
配置拒绝加载的四种冲突
- 两个生成器不得共用同一个
name。 宿主会解析第一个匹配项,使另一个生成器无法访问。 - 两个生成器不得指定同一个
templatePath。 验证时将无法判断匹配的实例属于哪个生成器。 - 名称不得为空,也不得包含路径分隔符。 名称会成为生成的 Nx 插件中的文件名。
- 名称不得为
all。validate --templates all已表示所有模板;若某个生成器也使用这个名称,同一个命令行参数就会有两种含义。
实例组:已有输出的存放位置
instances 是一个组列表,每组可选包含 patterns、exclude、tags、substitutions 和 threshold。设置分组是为了让不同路径集合使用不同的替换规则和符合度门槛。
exclude 用于列出相对于工作区的 glob,匹配的路径永远不会被视为实例。如果 exclude glob 匹配到由匹配模式找到的目录或文件,就会将其排除,无论是否设置了 tags。可用它排除与真实实例混在一起的第三方或生成代码,例如 shadcn 的组件输出:
exclude: ["projects/lexico/lexico-web/src/components/ui/**"]。
在 Nx 插件中,tags 会改变组的含义:
- 带有标签的组是项目选择器。 它适用于带有其中任一标签的所有项目,并会在每个选定项目内部读取其
patterns——因此src/modules/*在每个项目中都表示相同内容。 - 不带标签的组是普通工作区 glob,按原样使用。
- 带标签但不含模式的组只进行选择,不定位文件。 这样生成器就可以限定其可作用的项目,同时不验证任何内容。
目录模式和文件模式的行为不同,而这种差异决定了匹配项会由哪个模板胜出。各语言具体会如何比较,请参阅 references/languages.md。
输入
每个输入都是一个 JSON Schema 片段。以下键会生效;其他键均会被忽略:
| 键 | 作用 |
|---|---|
description | 提示词文本 |
enum | 将提示词变为列表,并限制可选值 |
minLength / maxLength | 长度验证 |
pattern | 按 Unicode 正则表达式进行匹配 |
两个宿主对于输入是否必填意见不一,而且无法通过配置更改。 Nx 插件会将所有已声明的输入标记为必填。命令行宿主则将所有输入标记为非必填。编写模板时,应确保缺少值会在输出中一目了然,而不要假定任一宿主的行为。
在 Nx 插件下,有四个输入名称具有额外含义,值得有意使用,而非不经意间使用:project、module、type 和 directory 都会影响输出位置。如果生成器所属的组带有标签,声明名为 project 的输入还会将其变成项目选择器。
config、help、instancePath 和 template 是保留名称,永远不会被视为输入——--template 是命令行宿主用于选择要渲染的模板的参数。name 则特意不设为保留名称。
钩子
生成器可以声明带有 preGenerate 和 postGenerate 的 hooks:宿主在生成前后运行的普通函数。你可以用它在写入任何内容之前拒绝无效输入,或编辑模板无法管理的文件,例如索引文件或 helm values 文件。
preGenerate在写入任何内容之前运行,此时generatedFilePaths为空。抛出异常即可拒绝本次运行。postGenerate在模板渲染完成后、格式化之前运行,此时generatedFilePaths已排序。
JSON 配置无法声明钩子,因为 JSON 无法包含函数;任何 JavaScript 或 TypeScript 配置都可以声明钩子。使用 @conformetry/configuration 中的 GeneratorHookContext 为钩子添加类型。以下三条规则可确保钩子在两个宿主下都能正常工作:
- 通过
context.filesystem写入,绝不要使用node:fs。 在 Nx 下,适配器会写入虚拟树,因此--dry-run和运行失败都不会留下改动。 - 为
context.filesystem提供工作区内的绝对路径,并基于context.configurationDirectoryPath构建。在 Nx 下,工作区外的路径会被重新定位到工作区内。 - 将写入的路径推入
context.generatedFilePaths,以便宿主对其进行格式化并报告。
在命令行宿主下,如果 postGenerate 抛出异常,已渲染的文件仍会留在磁盘上。生成 README 列出了完整的上下文表以及各宿主的错误行为,hooks 示例则会运行这两个钩子。
编写模板
文件夹本身就是定义。无需注册模板文件。
需要生成文件夹的模板必须包含该文件夹。 此时,其实例路径应设为该文件夹的_父级_。生成独立文件的模板则应将这些文件放在根目录下。如果弄错了,输出位置就会偏移一级。
占位符
渲染使用 Mustache,并关闭了 HTML 转义,因此请写 {{field}},
不要写 {{{field}}}。路径使用与内容相同的花括号:名为
{{nameKebabCase}}.service.ts 的文件会渲染为 orders.service.ts。
始终提供从名称派生的四种命名格式:
| 占位符 | search bar 的结果 |
|---|---|
{{nameCamelCase}} | searchBar |
{{nameKebabCase}} | search-bar |
{{namePascalCase}} | SearchBar |
{{nameSnakeCase}} | search_bar |
显式输入和配置的替换项最后应用,因此始终优先于同名的派生格式。
如果某个占位符没有对应的输入,生成会拒绝执行。 它会引发
MissingSubstitutionError,并指出占位符和模板文件,以便拼写错误能明确报错,而不是留下无声的空缺或空路径段。
如果某个占位符没有对应的输入,验证会从实例中读取该占位符。 它会为占位符渲染一个随机替代值,并照常进行比较。如果包含该替代值的模板节点与某个实例节点对齐,就会捕获实例中对应位置的文本。按文件顺序、再按文档顺序,首次捕获的值会被采用。随后会使用该值重新渲染模板并再次比较,因此后续使用该占位符的位置若包含不同文本,就会被视为普通差异。如果没有任何节点对齐,验证会报告
Could not infer {{path}}: no instance node aligned with the template text that uses it
并且无论阈值如何,实例都会验证失败。
name及其格式变体永远不会被推断;它们来自实例路径。- 配置的
substitutions值始终优先于推断值。 - 捕获方式遵循各语言自身的匹配规则:TypeScript 节点键(字符串字面量、声明名称,例如
class {{commandName}}Command、调用的第一个参数)、JSON 值、Markdown 节点文本(例如标题)以及纯文本行。占位符周围的字面文本必须完全匹配。Python、Jupyter、注释和文件路径不会捕获任何内容,因此只在这些位置使用的占位符必须显式提供。
以下两种情况仍然允许缺省,也是模板请求可选内容的方式:
- 区段标签。
{{#owner}}Owner: {{owner}}{{/owner}}和{{^owner}}Unowned.{{/owner}}是条件语句,因此缺少owner时不会报错,而是渲染为空。请在区段内插入变量,不要在区段外插入。 - 提供空值。
substitutions: { owner: "" }就是一个有效答案。只有缺少键才算空缺。
因此,只有当每个实例都在比较对齐的位置显示该值时,向模板添加占位符才对验证来说是安全的。否则,请在同一项更改中添加替换项。
没有条件文件机制
没有针对单个文件的谓词、扩展名过滤或跳过列表。树中的每个文件都会被渲染并写入。Mustache 区段可在内容内部使用,但由空占位符渲染出的路径会包含空段,而不是跳过文件。不要尝试寻找让文件变为可选的方法;这种机制不存在。
将值标记为可自由变化
包含 TODO 的注释是占位符:实例中的任意注释都能满足它。可将其用于在不同实例间确实会变化的说明性文字。
字符串字面量没有等效机制。 模板中的字符串必须逐字匹配,因此占位符说明或消息会成为每个实例的永久要求。最好将此类值留在模板之外,而不是固定成没人想要的措辞。
阈值
一致性按分数评定,而不只是通过或未通过;阈值是实例允许达到的最低分数。解析顺序由最具体到最宽泛:实例组的 threshold,然后是生成器的,再然后是运行级别的 --threshold,最后是 1。
除非正在迁移,否则不要设置。 默认值 1 表示完全匹配,这正是模板能成为标准而非建议的原因。将现有实例逐步迁移到新模板时,可以有意调低阈值,并在实例跟上后调高——永久调低的阈值意味着模板已无法描述其实例。
降低阈值不会抑制报告:通过了自身门槛的实例仍会显示差异。
更改配置后
Nx 生成器命名空间由配置生成,而且所有 conformetry 命令在命名空间过期时都会拒绝运行,而不是使用过时的定义:
nx sync
此部分涉及两种错误,它们都会指出各自的修复方法:
- 文件与配置不同步——运行
nx sync。 - 生成器指定的模板文件夹不存在——修正
templatePath,或创建该文件夹。
如果生成失败,依赖项安装只会发出警告,而不会失败,因此编辑到一半的配置不会导致所有人的安装中断。这也意味着此处的警告确实值得阅读。
检查你的工作
生成一个实例,然后检查它是否符合要求。新生成的实例按构造必然符合要求,因此任何差异都意味着模板与配置不一致——如何解读结果,请参阅 conformetry-validate 技能;生成步骤本身,请参阅 conformetry-generate。
与其阅读,不如亲自查看
conformetry-examples 包含 12 个自成一体的示例,每个示例都是一份完整配置,小到可以一口气读完。以下示例可以解答配置方面的问题:
hello-template— 必需的最少字段,以及模板的放置位置。case-variants— 派生变体,以及如何覆盖其中一个。scoring-thresholds— 两个实例组使用两个阈值,以及三个级别中哪一个优先。ambiguous-attribution— 两个模板声明同一路径时会报告什么,以及为什么重复声明同一个 glob 是个错误。nx-host— 按标签限定的实例组,以及没有项目图的宿主如何处理这些实例组。hooks— 拒绝不合规名称的preGenerate,以及写入回执的postGenerate。failure-modes— 未提供的占位符,且没有实例文本能揭示它;生成时会拒绝,验证时会报告。
完整索引请参阅其 AGENTS.md。