豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit 2e1eaba

Browse files
mvanhornOrKoNLightning00Blade
authored
chore: add eslint rule to validate tool schema patterns (#1191)
## Summary - Add `@local/no-zod-nullable-object` ESLint rule that disallows `.nullable()` and `.object()` usage in tool schema files (`src/tools/**/*.ts`) - Fix the existing `zod.object()` violation in `fill_form` by converting the elements array from objects to `"uid=value"` formatted strings - Remove the TODO from CONTRIBUTING.md and link the rule name to the documented restriction ## Context Per the [PR #1073 review](#1073 (comment)) and the CONTRIBUTING.md guidelines, tool schemas should not use `.nullable()` or `.object()` types. Complex objects should be represented as short formatted strings instead. The rule catches: - `zod.object({...})` / `z.object({...})` - flags direct zod object schema usage - `.nullable()` - flags nullable schema usage on any expression Closes #1076 ## Test plan - [ ] `npx eslint src/tools/` passes with no violations - [ ] Creating a test file with `zod.object()` or `.nullable()` in `src/tools/` triggers the rule - [ ] TypeScript compilation passes (`npx tsc --noEmit`) - [ ] Existing `fill_form` test updated to use new string format --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Alex Rudenko <OrKoN@users.noreply.github.com> Co-authored-by: Nikolay Vitkov <34244704+Lightning00Blade@users.noreply.github.com> Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
1 parent 47a50ca commit 2e1eaba

File tree

5 files changed

+78
-4
lines changed

5 files changed

+78
-4
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,5 @@ export const scenario: TestScenario = {
145145

146146
## Restrictions on JSON schema
147147

148-
- no .nullable(), no .object() types.
148+
- no .nullable(), no .object() types. Enforced by the `@local/enforce-zod-schema` ESLint rule.
149149
- represent complex object as a short formatted string.
150-
151-
TODO: implement eslint for schema https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1076

eslint.config.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ export default defineConfig([
135135
],
136136
},
137137
},
138+
{
139+
name: 'Tools definitions',
140+
files: ['src/tools/**/*.ts'],
141+
rules: {
142+
'@local/enforce-zod-schema': 'error',
143+
},
144+
},
138145
{
139146
name: 'Tests',
140147
files: ['**/*.test.ts'],
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @license
3+
* Copyright 2026 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
export default {
8+
name: 'enforce-zod-schema',
9+
meta: {
10+
type: 'problem',
11+
docs: {
12+
description:
13+
'Disallow .nullable() and .object() in tool schemas. Use optional strings to represent complex objects.',
14+
},
15+
schema: [],
16+
messages: {
17+
noNullable:
18+
'Do not use .nullable() in tool schemas. Use .optional() instead.',
19+
noObject:
20+
'Do not use .object() in tool schemas. Represent complex objects as a short formatted string.',
21+
},
22+
},
23+
defaultOptions: [],
24+
create(context) {
25+
return {
26+
CallExpression(node) {
27+
if (
28+
node.callee.type !== 'MemberExpression' ||
29+
node.callee.property.type !== 'Identifier'
30+
) {
31+
return;
32+
}
33+
34+
const methodName = node.callee.property.name;
35+
36+
// We don't validate that .nullable() is called on a ZodObject
37+
// specifically - this intentionally catches all .nullable() calls
38+
// in tool schema files.
39+
if (methodName === 'nullable') {
40+
context.report({
41+
node: node.callee.property,
42+
messageId: 'noNullable',
43+
});
44+
}
45+
46+
if (methodName === 'object') {
47+
// Only flag zod.object() calls, not arbitrary .object() calls.
48+
const obj = node.callee.object;
49+
if (
50+
obj.type === 'Identifier' &&
51+
(obj.name === 'zod' || obj.name === 'z')
52+
) {
53+
context.report({
54+
node: node.callee.property,
55+
messageId: 'noObject',
56+
});
57+
}
58+
}
59+
},
60+
};
61+
},
62+
};

scripts/eslint_rules/local-plugin.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,11 @@
55
*/
66

77
import checkLicenseRule from './check-license-rule.js';
8+
import enforceZodSchemaRule from './enforce-zod-schema-rule.js';
89

9-
export default {rules: {'check-license': checkLicenseRule}};
10+
export default {
11+
rules: {
12+
'check-license': checkLicenseRule,
13+
'enforce-zod-schema': enforceZodSchemaRule,
14+
},
15+
};

src/tools/input.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ export const fillForm = definePageTool({
322322
schema: {
323323
elements: zod
324324
.array(
325+
// eslint-disable-next-line @local/enforce-zod-schema
325326
zod.object({
326327
uid: zod.string().describe('The uid of the element to fill out'),
327328
value: zod.string().describe('Value for the element'),

0 commit comments

Comments
 (0)