关于 project-validator
project-validator 是面向 Datex Studio 的项目级只读检查技能,适合在合并批次或发布前审查分支配置。它从分支导出配置,并执行五类跨组件检查,补充单文件验证无法发现的问题。
主要功能
- 01从分支枚举并导出配置
- 02执行五类项目级检查
- 03检查描述与类型引用
- 04预检 OData 架构和查询
- 05按检查类别整理问题清单
- 06只读运行,不修改分支
适用场景
- 01合并前检查一批配置
- 02发布前扫描整个项目
- 03仅检查指定配置类型
- 04定位跨文件引用或架构问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ datex/ skills --skill project-validator安装后在 Claude Code 中输入/project-validator确认已加载。
详细介绍
项目验证器
针对 Datex Studio 分支进行项目级 lint 检查。分支是真实来源:验证器通过 dxs source explore configs 枚举分支中的配置,并通过 dxs source document build(CLI 的离线分析路径)将其批量导出到临时目录,然后针对该临时导出运行五项跨组件检查——这些检查无法通过逐文件验证单独完成。返回按检查类型分组的结构化只读待办清单。绝不修改分支,也绝不将本地 src/ 检出目录视为权威来源。
这是项目级验证器。它与逐文件验证相辅相成:component-validator 根据特定类型的规则表端到端审核单个组件文件;本技能则审核整个项目(或指定范围的子集),查找只有跨文件检查时才会出现的问题——例如失效的 objectType 引用、与实时架构不匹配的 OData 查询、偏离已声明 outParams 的数据源查询选项等。这两项技能旨在配合使用——每个文件编写完成后使用 component-validator,合并一批更改或发布版本前使用 project-validator。
另请参阅:
component-validator— 根据各类型的创建规则表审核单个文件。在编写或修改任何组件后使用。本技能是它在项目级别的对应工具。另请参阅:
component-wiring-check— 追踪特定的跨组件引用约定。本技能覆盖面更广(涵盖整个项目的 5 类问题),但检查较浅(lint 级别,而非深入的连线追踪)。另请参阅:
post-edit-verification— 写入单个文件后的快速检查。其范围与本技能不同,检查也更轻量。
依赖项
datex-studio-conventions—defaults.md(描述 ≤100 个字符、描述必填)、file-format.md(configurationTypeId表、后缀规则)、naming-conventions.md(类型标识规则)。以下检查所执行的规则均来自这些文档。datex-studio-shared/datex-studio-runtime— 用于解析流程代码的分支设置基础工具和平台运行时全局对象(例如解析$flow.inParams.<name>和$flow.outParams.<name>引用)。component-validator— 逐文件配套工具,范围相邻。当项目验证器发现某个文件局部违规,而创建技能的规则表中详细记录了该问题时,应将用户引导至component-validator进行深入审核。schema-explorer— 用于 OData 预检(检查 4)。项目验证器不得将原始架构文档加载到父上下文中——始终将实体、属性和导航项查询委托给schema-explorer。codebase-research— 当某项发现需要基于依据只读检查支持上下文时调用(例如从分支获取*-customType配置,以确认枚举的允许值)。可选,按需使用。
模式
这是只读的项目 lint 检查。不要修改任何文件。不要运行会更改分支状态的命令(不得使用 upsert、--fix 或写入操作)。验证器只负责报告;由父级决定如何处理发现的问题,并将修复任务交回相应的创建者/编辑器技能。
工作流
1. 确定范围
验证器始终针对一个分支运行(遵循 datex-studio-shared/branch-setup.md 来确定分支 ID——切勿自行假设)。调用方还需提供以下选项之一:
all(默认)— 分支上的所有自有配置。- 一个检查名称 —
descriptions、schema、types、metadata、result-shapes。仅针对整个项目运行该项检查。 - 一个范围子集 — 一种或多种配置类型(例如
grid、datasource),或名称模式。仅在该子集中运行全部五项检查(或指定的检查)。
如果调用方的要求不明确(例如只说“验证项目”),则默认检查分支上的所有自有配置,并在输出中说明所选范围。
2. 枚举并导出目标配置(来自分支)
分支是唯一可信来源——不要遍历本地的 src/ 检出目录。通过 CLI 获取配置:
# List what's on the branch (optionally filter by type / owned-only / scope)
dxs source explore configs --branch <branchId> --owned-only
# Bulk-export every config to a THROWAWAY temp dir for offline analysis
dxs source document build --branch <branchId> --include-summaries -o "$TMP/dxs-validate"
document build 会在 $TMP/dxs-validate/<App>/<branchId>/local/<type>/<referenceName>.yaml 下为每个配置写入一个文件。这些临时导出文件是检查唯一会读取或搜索的文件——搜索刚获取的临时文件是允许的做法;搜索持久化的 src/ 树则不允许。完成后删除临时目录。
在 dxs < 0.5.4 中,此导出会悄无声息地不完整——需要 dxs ≥ 0.5.4。 库发现逻辑依赖于一个
applicationId,而从设置/引用迁移到AppConfig时,每个引用行中的这个字段都被移除了,因此document build只会遍历分支本身;由于每次分支遍历都会按设计排除外部配置,所有库配置都不会出现在导出中——命令退出码为 0,且没有任何警告。将名称解析到被引用的包中的检查(types、schema、result-shapes)随后会把这些缺失项视为“组件缺失”,并产生误报。较旧版本生成的干净运行结果不代表任何信息,不能视为通过:请升级(dxs update)。从 0.5.4 起,导出会包含库分支,并会针对仍无法定位的库打印Warning: could not resolve library '<name>' to a branch——这同样意味着存在缺口,只是这次会在运行过程中报告,请据此确定受影响检查的范围。
按类型对导出的配置分组(导出文件已按类型放在不同文件夹中,且每个配置都带有 configurationTypeId):
footprintflow— 操作(*-footprintFlow)flow— 函数(*-flow)customtype— 接口 / 枚举(*-customType)footprintdatasource— Footprint 级 OData 数据源datasource— 云级数据源(OData 或由 flow 提供支持)selector、storage、grid、form、editor、hub、backendtest
类型与表格不匹配的配置记为 unknown component type 并跳过(不要因此阻止运行)。
3. 运行 5 项检查
针对枚举出的文件运行每项检查。顺序不限;可先运行成本最低的检查。将发现项收集为结构化列表,绝不就地编辑。
4. 报告
按照下方的输出格式部分编写待办清单。按检查类型对发现项分组。最后用一行总结(total files checked、passes、warnings、failures)。除一句简短的指引外,不要提出修复建议。
5 项检查
1. 描述验证(descriptions)
扫描对象: 每个组件文件(所有上述后缀)。
规则(来自 datex-studio-conventions/defaults.md 和 file-format.md):
description不得为null。description不得为""(空字符串)。description必须不超过 100 个字符。这是 Footprint 端 SQL 列的硬性上限——超出上限会导致导入因 SQL 截断错误而失败。
严重程度:
description为null或""→ 失败。description超过 100 个字符 → 失败(不是警告——导入会失败)。description存在且未超出上限 → 通过。
输出行:
[pass] i_awi_configuration-customType.json — "Allocation config interface" (35 chars)
[FAIL] my_action-footprintFlow.json — description is null
[FAIL] orders_grid-grid.json — description is 137 chars (cap is 100)
2. Schema 与代码对齐(schema)
**扫描对象:**操作文件(*-footprintFlow.json)和函数文件(*-flow.json)。
**检查内容:**声明的 inParams / outParams JSON 与嵌入的 TypeScript 代码是否一致;代码位于 nodes[0].stepConfig.executeCodeConfig.code(根据 codebase-research 中记录的模式,流程代码位于 JSON 内部,而非 JSON 顶层)。
流程:
- 从 JSON 中解析
inParams[]和outParams[]。 - 提取嵌入的代码字符串(对于多步骤流程,遍历
nodes[*])。 - 使用启发式匹配,检查代码中的
$flow.inParams.<id>引用是否对应每个已声明的inParam.id。 - 使用启发式匹配,检查代码中的
$flow.outParams.<id>引用是否对应每个已声明的outParam.id。 - 查找代码中没有对应声明的
$flow.inParams.<name>或$flow.outParams.<name>引用。
严重级别:
- 已声明的
inParam未在代码中引用 → 警告(可能是有意保留,以兼容旧版本、供将来使用,或用于外部连线)。 - 已声明的
outParam从未在代码中赋值 → 警告。 - 代码引用了没有对应声明的
$flow.inParams.<name>/$flow.outParams.<name>→ 失败(会导致运行时错误或静默返回undefined)。
**注意:**这只是启发式字符串匹配,并非 TypeScript 编译器。发现误报时可以将其列为警告,由调用方判断每条警告是否属实。没有基于源代码的确凿证据时,不要将警告升级为失败。
输出行:
[warn] plan_inventory_consumption_action — inParam 'unused_param' declared but not referenced in code
[FAIL] commit_allocation_plan_action — code references $flow.inParams.foo but 'foo' is not declared in inParams
3. 类型解析(types)
**扫描对象:**每个组件文件。在 JSON 中查找任意位置的 "objectType": "<Package>.<TypeName>" 值(通常位于 inParams[*].objectType、outParams[*].objectType、objectTypeDef.properties[*].objectType 以及嵌套的数据源结构中)。
**规则:**每个被引用的 <Package>.<TypeName> 都必须能解析为以下类型之一:
- 当前分支上由当前包拥有的
<TypeName>customType配置(临时导出中的customtype/<TypeName>-customType.*条目;等价查询为dxs source explore configs --branch <id> --type customtype --search <TypeName>),或 - 项目所依赖的其他包拥有的类型(将未知包视为“超出范围,不报告”,除非调用方明确要求追查跨包引用)。
流程:
- 确定当前包(从该包的一个组件文件中读取;通过文件夹约定进行交叉核对)。
- 收集所有已扫描组件文件中的每个
objectType字符串。 - 对每个包内引用,验证分支上是否存在对应的
<TypeName>customType 配置(位于临时导出的customtype/文件夹中)。**快速解析捷径:**一次性获取分支的命名法注册表 —dxs configuration nomenclature -b <branchId>会返回扁平的<Package>.<Type>目录(枚举成员位于constantValues中),可一次性检查每个objectType是否存在,而无需逐个类型执行dxs source explore查询。参见 ../datex-studio-shared/context-navigation.md#discovering-custom-types-and-enum-members。 - 报告无法解析的引用。
严重级别:
- 引用当前包中的类型,但分支上没有对应的 customType 配置 → 失败。
- 引用的包不属于项目 → 警告(可能是拼写错误,也可能是合法的外部包)。
输出行:
[FAIL] orders_grid-grid.json — references `Allocations.i_unknown_type`, no i_unknown_type-customType.json found
[warn] import_orders_action-footprintFlow.json — references `ExternalPkg.i_thing`; ExternalPkg is unknown to this project
4. OData 架构预检(metadata)
扫描: OData 数据源文件——*-footprintDatasource.json,以及 type 为 "oDataQuery" 的 *-datasource.json 文件。跳过由流程支持的数据源。
流程:
- 解析连接。 每个数据源都引用一个连接(连接 ID 或连接名称)。从文件中确定连接。如果有歧义,请询问调用方要针对哪个连接进行验证。
- 每次实体 / 属性 / 导航查找都委托给
schema-explorer。不要将原始 OData 元数据文档加载到父上下文中——schema-explorer会返回简洁的结构化答案,并处理连接解析和 FootPrintApi 特殊情况。 - 对每个 OData 数据源:
- 确认 OData 架构中存在
paths[0].entitySet中的entitySet。 - 确认
queryOptions.selects中的每个属性都存在于实体类型中。 - 确认
queryOptions.filters中引用的每个属性(筛选表达式操作数)都存在于实体类型中。 - 确认
queryOptions.expands中的每个导航属性都存在于实体类型中。
- 确认 OData 架构中存在
- 报告不匹配项。
严重程度:
- 缺少实体集 → 失败。
- 缺少 select / filter 属性 → 失败。
- expand 中缺少导航属性 → 失败。
- 架构查找失败(连接无法访问、架构未加载)→ 警告,并注明无法对此文件运行检查。单个连接无法访问时,不要判定整个运行失败——记录警告并继续。
输出行:
[FAIL] fpds_get_material-footprintDatasource.json — entitySet 'Materials' not found in schema (did you mean 'Material'?)
[FAIL] ds_orders_grid-datasource.json — selects: property 'CustomeName' not on entity 'Orders' (typo?)
[warn] ds_legacy_thing-datasource.json — could not reach connection 'LegacyProd'; check skipped
5. 结果形状同步(result-shapes)
扫描: 所有数据源文件(包括 *-datasource.json 和 *-footprintDatasource.json,以及 OData 和由流程支持的数据源)。
规则: 数据源的查询端形状(queryOptionsObjectTypeDef)和面向使用者的形状(outParams[0].objectTypeDef)必须一致。一侧的每个属性都应在另一侧有匹配项,且 id 和 type 相同。这两项声明不一致,是“数据源在 Studio 预览中正常工作,但会导致使用者出错”的典型故障模式。
流程:
- 从文件中读取
queryOptionsObjectTypeDef.properties[]。 - 从文件中读取
outParams[0].objectTypeDef.properties[]。 - 按
id配对属性。 - 标记一侧存在但另一侧没有对应项的属性,或
id配对项中type不同的属性。
严重程度:
- 属性仅存在于一侧,另一侧缺失 → 失败。
- 属性配对项的
type不匹配 → 失败。 - 属性配对项的
id和type相同,但顺序 / 元数据不同 → 小问题。
输出行:
[FAIL] ds_open_orders-datasource.json — `queryOptionsObjectTypeDef.OrderId` is `int32`, `outParams[0].objectTypeDef.OrderId` is `string`
[FAIL] fpds_lots-footprintDatasource.json — `outParams[0].objectTypeDef` declares property `LotCode`, missing from `queryOptionsObjectTypeDef`
输出格式
按检查类型分组列出发现项,顺序与上述五项检查一致。每组内先列失败项,再列警告,最后列小问题。通过项行可选——调用方要求详细运行时包含,否则在默认 lint 摘要中省略。始终以一行摘要结尾。
## 1. Description Validation
[FAIL] my_action-footprintFlow.json — description is null
[FAIL] orders_grid-grid.json — description is 137 chars (cap is 100)
[pass] i_awi_configuration-customType.json — "Allocation config interface" (35 chars)
...
## 2. Schema-Code Alignment
[FAIL] commit_allocation_plan_action — code references $flow.inParams.foo but 'foo' is not declared in inParams
[warn] plan_inventory_consumption_action — inParam 'unused_param' declared but not referenced
## 3. Type Resolution
[FAIL] orders_grid-grid.json — references `Allocations.i_unknown_type`, no i_unknown_type-customType.json found
## 4. OData Schema Pre-Flight
[FAIL] fpds_get_material-footprintDatasource.json — entitySet 'Materials' not found (did you mean 'Material'?)
[warn] ds_legacy_thing-datasource.json — could not reach connection 'LegacyProd'; check skipped
## 5. Result-Shape Sync
[FAIL] ds_open_orders-datasource.json — `OrderId` type drift: query=int32, outParams=string
## Summary
files checked: 142
passes: 128
warnings: 7
failures: 7
scope: all
如果检查已运行且未发现问题,请在相应标题下写 (no issues),而不要省略该标题——明确标注为空比不作说明更清晰。
规则
- 只读。 不要修改任何文件。不要自动修复。不要运行会修改内容的
dxs命令。验证器的任务是报告问题;由父级(或用户)决定后续操作。 - 列出待办,不要重写。 每条发现都应是一行引用,包含文件路径和简短的证据行。不要提供冗长的代码建议或拟议的 JSON。如果修复方式不明显,请指出负责该修复的对应创建者技能(例如“交由
datasource-creator处理”),而不是描述修复本身。 - 将 OData 架构交给
schema-explorer。 绝不要将原始 OData 元数据载入父级上下文。这是 Datex Studio 工作中最严重的上下文污染反模式。 - 启发式检查只能发出警告,不能判定失败。 尤其是架构与代码对齐检查,它是字符串匹配 lint,不是编译器。对于“可能确有问题”的情况使用
warning,只有证据明确无误时才使用fail。 - 遵守范围限制。 调用方指定检查名称时,只运行该检查。调用方指定子树时,只遍历该子树。不要自行扩大范围。
- 不要猜测意图。 如果违规可能是有意为之(例如为外部接线而保留的
inParam,或出于前瞻性考虑而声明范围宽于查询的outParams),应附注并标记为警告,而不是失败。 - 每次调用只运行一次。 不要反复运行验证器,直到“全部通过”。列出待办后交由父级决定是否继续迭代。
- 以分支为准。 使用
dxs source explore configs/dxs source document build从分支枚举并导出配置。不要将本地src/检出内容视为权威来源。 - 不得写入分支,不得提供修复补丁。 唯一允许的本地产物是临时的
dxs source document build导出文件,检查会读取该文件,完成后应将其删除。报告直接放在响应正文中返回——不要创建references/、日志或补丁文件。