name: code-sample-validator description: 提取、验证和测试文档中的代码示例。验证语法、执行示例、检查输出、验证导入,并确保代码示例与当前API保持同步。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep backlog-id: SK-008 metadata: author: babysitter-sdk version: “1.0.0”
代码示例验证技能
提取、验证和测试文档中的代码示例。
能力
- 从Markdown/MDX中提取代码块
- 多种语言的语法验证
- 执行并验证代码示例输出
- 代码片段编译测试
- 版本兼容性检查
- 导入/依赖项验证
- 代码格式验证(prettier, black)
- 从文档生成可运行代码
用法
在以下情况时调用此技能:
- 验证文档中的代码示例
- 测试代码示例是否正确执行
- 检查过时的API用法
- 验证导入语句
- 从文档生成测试文件
输入
| 参数 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
| inputPath | string | 是 | 文档文件或目录的路径 |
| action | string | 是 | 提取、验证、执行、格式化 |
| languages | array | 否 | 按语言过滤(js, python等) |
| outputDir | string | 否 | 用于存放提取的可运行代码的目录 |
| timeout | number | 否 | 执行超时时间(秒) |
| config | object | 否 | 语言特定配置 |
输入示例
{
"inputPath": "./docs",
"action": "validate",
"languages": ["javascript", "python"],
"timeout": 30
}
输出结构
验证报告
{
"summary": {
"total": 45,
"passed": 42,
"failed": 2,
"skipped": 1
},
"files": [
{
"file": "docs/quickstart.md",
"samples": [
{
"language": "javascript",
"line": 15,
"status": "passed",
"syntaxValid": true,
"executionResult": {
"success": true,
"output": "Hello, World!",
"duration": 125
}
},
{
"language": "python",
"line": 45,
"status": "failed",
"syntaxValid": true,
"executionResult": {
"success": false,
"error": "ModuleNotFoundError: No module named 'requests'",
"suggestion": "将'requests'添加到测试依赖项中"
}
}
]
}
],
"issues": [
{
"file": "docs/api/users.md",
"line": 78,
"language": "typescript",
"issue": "类型错误:类型'Response'上不存在属性'user'",
"code": "const name = response.user.name;",
"suggestion": "更新为使用'response.data.user.name'"
}
]
}
代码提取
Markdown代码块模式
```javascript
// 此代码块将被提取和验证
const client = new Client({ apiKey: 'test' });
const result = await client.query('Hello');
console.log(result);
```
```python
# 此代码块将被提取和验证
from mypackage import Client
client = Client(api_key='test')
result = client.query('Hello')
print(result)
```
```bash skip-validation
# 由于指令,此代码块将被跳过
echo "Not validated"
```
```javascript title="example.js" runnable
// 此代码块被标记为可运行
export function greet(name) {
return `Hello, ${name}!`;
}
```
提取配置
{
"extract": {
"includeLanguages": ["javascript", "typescript", "python", "go"],
"excludeLanguages": ["bash", "shell", "text"],
"directives": {
"skip": ["skip-validation", "no-test"],
"runnable": ["runnable", "test"],
"expectError": ["expect-error"]
},
"metaPatterns": {
"title": "title=\"([^\"]+)\"",
"filename": "filename=\"([^\"]+)\""
}
}
}
语言特定验证
JavaScript/TypeScript
// validator-config.js
module.exports = {
javascript: {
parser: 'babel',
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module'
},
execute: {
runtime: 'node',
timeout: 10000,
setup: `
global.fetch = require('node-fetch');
process.env.API_KEY = 'test-key';
`
},
format: {
tool: 'prettier',
config: {
semi: true,
singleQuote: true,
trailingComma: 'es5'
}
}
},
typescript: {
compiler: 'tsc',
compilerOptions: {
target: 'ES2022',
module: 'ESNext',
strict: true
},
execute: {
runtime: 'ts-node',
timeout: 15000
}
}
};
Python
# validator_config.py
PYTHON_CONFIG = {
'version': '3.11',
'execute': {
'timeout': 30,
'setup': '''
import os
os.environ['API_KEY'] = 'test-key'
''',
'virtualenv': '.venv'
},
'format': {
'tool': 'black',
'config': {
'line_length': 88,
'target_version': ['py311']
}
},
'lint': {
'tool': 'ruff',
'rules': ['E', 'F', 'W']
}
}
Go
// validator_config.go
package main
var GoConfig = Config{
Version: "1.21",
Execute: ExecuteConfig{
Timeout: 30,
Build: true,
Run: true,
},
Format: FormatConfig{
Tool: "gofmt",
},
Lint: LintConfig{
Tool: "golangci-lint",
Rules: []string{"govet", "errcheck", "staticcheck"},
},
}
测试生成
生成测试文件
// 从docs/quickstart.md生成
const { Client } = require('@example/sdk');
describe('文档代码示例', () => {
describe('quickstart.md', () => {
test('第15行:基本客户端用法', async () => {
const client = new Client({ apiKey: 'test' });
const result = await client.query('Hello');
expect(result).toBeDefined();
});
test('第45行:错误处理', async () => {
const client = new Client({ apiKey: 'invalid' });
await expect(client.query('Hello')).rejects.toThrow('Invalid API key');
});
});
});
测试配置
{
"testGeneration": {
"framework": "jest",
"outputDir": "tests/docs",
"filePattern": "{docfile}.test.js",
"imports": [
"const { Client } = require('@example/sdk');",
"const { mockServer } = require('./mocks');"
],
"beforeAll": "await mockServer.start();",
"afterAll": "await mockServer.stop();",
"assertions": {
"outputMatch": true,
"noThrow": true,
"typeCheck": true
}
}
}
CI/CD集成
GitHub Actions
name: 验证文档
on:
push:
paths:
- 'docs/**/*.md'
pull_request:
paths:
- 'docs/**/*.md'
jobs:
validate-code-samples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: 安装依赖
run: |
npm ci
pip install -r requirements-docs.txt
- name: 验证代码示例
run: |
node scripts/validate-docs.js \
--input docs/ \
--languages javascript,python \
--report validation-report.json
- name: 上传报告
if: always()
uses: actions/upload-artifact@v4
with:
name: validation-report
path: validation-report.json
- name: 检查失败
run: |
if jq '.summary.failed > 0' validation-report.json | grep -q true; then
echo "代码示例验证失败"
jq '.issues' validation-report.json
exit 1
fi
格式验证
Prettier检查
const prettier = require('prettier');
async function validateFormatting(code, language) {
const options = {
parser: getParser(language),
semi: true,
singleQuote: true,
trailingComma: 'es5',
};
try {
const formatted = await prettier.format(code, options);
const isFormatted = code === formatted;
return {
valid: isFormatted,
formatted: formatted,
diff: isFormatted ? null : generateDiff(code, formatted),
};
} catch (error) {
return {
valid: false,
error: error.message,
};
}
}
Black检查(Python)
import black
import difflib
def validate_formatting(code: str) -> dict:
try:
mode = black.Mode(
target_versions={black.TargetVersion.PY311},
line_length=88,
)
formatted = black.format_str(code, mode=mode)
is_formatted = code == formatted
return {
'valid': is_formatted,
'formatted': formatted,
'diff': None if is_formatted else list(
difflib.unified_diff(
code.splitlines(),
formatted.splitlines(),
lineterm=''
)
)
}
except black.InvalidInput as e:
return {
'valid': False,
'error': str(e)
}
工作流程
- 提取示例 - 解析Markdown中的代码块
- 过滤 - 应用语言和指令过滤器
- 验证语法 - 检查语法错误
- 检查导入 - 验证依赖项是否存在
- 执行 - 在沙箱中运行示例
- 验证输出 - 检查预期结果
- 检查格式 - 验证代码风格
- 报告 - 生成验证报告
依赖项
{
"devDependencies": {
"@babel/parser": "^7.23.0",
"prettier": "^3.0.0",
"typescript": "^5.3.0",
"ts-node": "^10.9.0",
"jest": "^29.7.0",
"gray-matter": "^4.0.0"
}
}
CLI命令
# 验证所有示例
node scripts/validate-docs.js --input docs/
# 提取并保存可运行代码
node scripts/validate-docs.js --input docs/ --action extract --output tests/samples/
# 生成测试文件
node scripts/validate-docs.js --input docs/ --action generate-tests --output tests/docs/
# 仅检查格式
node scripts/validate-docs.js --input docs/ --action format-check
最佳实践应用
- 使用指令标记不可运行的示例
- 包含用于验证的预期输出
- 在示例中使用一致的格式
- 在示例中固定依赖版本
- 在CI/CD管道中测试示例
- 从文档生成可运行的测试
参考
- Prettier: https://prettier.io/
- Black: https://black.readthedocs.io/
- MDX: https://mdxjs.com/
- Jest: https://jestjs.io/
目标流程
- docs-testing.js
- api-reference-docs.js
- sdk-doc-generation.js
- interactive-tutorials.js