ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

2小时零代码实战:基于AI协作开发生产级VSCode JSON Schema插件

2小时零代码实战:基于AI协作开发生产级VSCode JSON Schema插件 1. 从零到一一个VSCode插件的诞生契机最近在做一个新项目需要频繁地处理一种特定格式的JSON配置文件。每次修改我都得手动去检查字段名是否正确、结构是否合规偶尔还会因为手滑多打一个逗号导致整个文件解析失败调试起来相当费神。这种重复、机械且容易出错的校验工作让我萌生了一个想法能不能在VSCode里写这个配置文件时编辑器就能实时给我提示和校验就像写TypeScript代码有类型检查一样这个需求很明确一个轻量级的VSCode插件能针对我自定义的JSON Schema进行实时校验、智能补全和悬浮提示。按照传统路径我需要先学习VSCode插件的官方文档用Yeoman脚手架生成项目骨架然后吭哧吭哧地写TypeScript代码处理各种API调用、生命周期、事件监听……没个一两天功夫估计连Demo都跑不顺。但这次我决定换一种方式。我手头正好有Claude一个以代码理解和生成能力见长的AI助手。我很好奇如果我把需求清晰地告诉它让它来主导整个开发流程而我主要负责提供思路、审核代码和调试最终能走多远这个实验的目标很直接在2小时内不亲手写一行核心业务代码完全依靠与Claude的对话构建出一个能实际运行、功能完整的“生产级”VSCode插件原型。这里的“生产级”不是指能直接上应用商店而是指它具备一个正经插件该有的核心要素清晰的项目结构、符合规范的代码、可工作的核心功能、以及便于他人理解和扩展的代码组织。整个过程我的角色更像是一个产品经理兼测试工程师而Claude则扮演了全栈开发工程师。2. 与AI结对编程明确需求与搭建骨架和人类工程师协作一样与AI协作的第一步也是最关键的一步就是清晰地定义需求。模糊的指令只会得到模糊甚至错误的结果。我没有一上来就说“帮我写个VSCode插件”而是准备了一份详细的“产品需求文档”发给Claude。我的需求描述大致是这样的 “我需要一个VSCode插件用于支持一种自定义的.myconfig文件格式。这种文件本质上是JSON但必须遵循一个特定的结构即JSON Schema。核心功能有三个语法校验当文件内容不符合我定义的Schema时在问题面板Problems和编辑器的波浪线下划线上显示错误。代码补全在编辑时能根据Schema提供字段名、枚举值的自动补全建议。悬浮提示鼠标悬停在字段或值上时能显示来自Schema的描述信息description。这是我定义的Schema示例一个简单的应用配置{ $schema: http://json-schema.org/draft-07/schema#, type: object, properties: { appName: { type: string, description: The name of the application. }, version: { type: string, pattern: ^\\\\d\\\\.\\\\d\\\\.\\\\d$, description: Semantic version number. }, environment: { type: string, enum: [development, staging, production], description: Deployment environment. }, port: { type: integer, minimum: 1024, maximum: 65535, description: Port number the app listens on. }, features: { type: object, properties: { logging: { type: boolean }, debug: { type: boolean } } } }, required: [appName, version] }请基于此为我生成一个完整的VSCode插件项目使用TypeScript开发。”这个需求描述包含了目标、具体功能点、输入输出示例非常具体。Claude的回复也立刻进入了状态。它没有直接给我一大段代码而是先给出了一个项目创建与初始化的步骤清单环境准备确保本地已安装Node.js16.x和VSCode。使用官方生成器通过npm install -g yo generator-code安装Yeoman和VSCode插件生成器。生成项目运行yo code并交互式地选择“New Extension (TypeScript)”输入插件名称如myconfig-helper、描述等。安装依赖进入项目目录执行npm install。注意这里出现了一个有趣的细节。Claude建议的步骤是标准流程但为了追求“0行手写代码”我实际上跳过了第2、3步。我直接要求Claude为我生成package.json、tsconfig.json等所有项目配置文件的内容以及src/extension.ts的骨架代码。我手动创建文件夹和文件然后将Claude生成的内容粘贴进去。这相当于让AI直接输出了“yo code”命令的结果省去了交互过程。这是与AI协作的一个小技巧当你明确知道标准流程的输出时可以直接要求AI生成那个结果从而跳过工具执行步骤。接下来Claude生成了核心的package.json的contributes部分这是插件功能的声明式配置contributes: { languages: [{ id: myconfig, aliases: [MyConfig, myconfig], extensions: [.myconfig], configuration: ./language-configuration.json }], grammars: [{ language: myconfig, scopeName: source.myconfig, path: ./syntaxes/myconfig.tmLanguage.json }], jsonValidation: [{ fileMatch: *.myconfig, url: ./schemas/myconfig-schema.json }] }这段配置做了三件事languages告诉VSCode.myconfig后缀的文件是一种新语言我们称之为“myconfig”并关联了一个语言配置文件用于定义括号自动配对、注释符号等。grammars关联了语法高亮规则文件TextMate语法让我们的配置文件能有色彩。jsonValidation这是实现离线校验的关键。它声明所有.myconfig文件都遵循位于项目./schemas/目录下的myconfig-schema.json这个Schema。VSCode内置的JSON语言服务会据此进行基础校验。Claude随后生成了language-configuration.json和myconfig.tmLanguage.json的初始内容。对于语法高亮文件它采用了基于JSON的TextMate语法将myconfig文件的ScopeName设置为source.myconfig并初步定义了如何匹配字符串、数字、常量等基础语法元素。至此项目的骨架和“静态”声明部分已经由Claude搭建完毕。我只需要按照它给出的文件树结构创建文件夹和文件并粘贴内容即可。整个过程没有遇到障碍因为这些都是非常标准化、模式化的配置。3. 核心功能实现动态校验、补全与提示静态的JSON校验通过jsonValidation已经实现但这只是基础。我们需要更强大的、动态的语言功能智能补全和悬浮提示。这需要编写TypeScript代码在插件激活时向VSCode注册相应的提供器Provider。我向Claude提出了下一步需求“现在请实现src/extension.ts注册一个CompletionItemProvider和一个HoverProvider让它们对.myconfig文件生效。补全和悬停的内容需要基于我之前提供的那个JSON Schema来生成。”Claude的响应非常迅速它生成了extension.ts的完整代码。其核心逻辑可以拆解如下3.1 插件激活与资源管理插件的主入口文件extension.ts在activate函数中启动。Claude生成的代码首先尝试读取项目内的Schema文件。import * as vscode from vscode; import * as path from path; import * as fs from fs; let schema: any null; export function activate(context: vscode.ExtensionContext) { // 1. 加载Schema文件 const schemaPath path.join(context.extensionPath, schemas, myconfig-schema.json); try { const schemaContent fs.readFileSync(schemaPath, utf-8); schema JSON.parse(schemaContent); console.log(MyConfig schema loaded successfully.); } catch (error) { vscode.window.showErrorMessage(Failed to load MyConfig schema: ${error}); return; // 如果Schema加载失败插件核心功能无法工作 } // ... 注册Provider }这里有一个重要的实践细节将Schema文件作为插件资源的一部分放在schemas/目录而不是硬编码在TypeScript里。这样做的好处是未来如果需要更新Schema直接修改这个JSON文件即可无需重新编译和发布插件代码维护性更好。Claude的这个设计是符合生产级思维的。3.2 实现智能补全提供器 (CompletionItemProvider)补全提供器的核心是provideCompletionItems方法。Claude生成的逻辑充分考虑了JSON的结构特性解析当前位置通过分析文档内容和光标位置判断用户当前是在输入对象{之后、数组[之后还是键值对。提取访问路径例如当光标在features: { “|” }时算法能解析出当前路径是properties.features.properties。查询Schema根据路径从加载的Schema对象中找到对应的properties定义。生成补全项为每个有效的属性名创建一个vscode.CompletionItem并将其kind设置为vscode.CompletionItemKind.Property使其在补全列表中显示为属性图标。同时将Schema中的description填入documentation字段这样用户在补全列表里就能看到提示。const completionProvider vscode.languages.registerCompletionItemProvider( myconfig, { async provideCompletionItems(document, position) { // 获取当前行的文本和光标前的文本 const linePrefix document.lineAt(position).text.substr(0, position.character); // 简易解析判断是否在引号内、是否在对象内部等 // 这里Claude实现了一个简易的JSON解析状态机来获取当前路径 const currentPath parseJsonPath(document, position); if (!currentPath.isInPropertyKey currentPath.isInObjectValue) { // 场景正在输入对象的属性名 let targetSchema schema; for (const segment of currentPath.pathSegments) { if (targetSchema.properties targetSchema.properties[segment]) { targetSchema targetSchema.properties[segment]; } else if (targetSchema.items) { targetSchema targetSchema.items; // 处理数组 } else { break; } } const suggestions: vscode.CompletionItem[] []; if (targetSchema.properties) { for (const [propName, propSchema] of Object.entries(targetSchema.properties)) { const item new vscode.CompletionItem(propName, vscode.CompletionItemKind.Property); item.documentation (propSchema as any).description || Property \${propName}\; // 自动插入引号和冒号提升体验 item.insertText ${propName}: ; suggestions.push(item); } } return suggestions; } // 处理枚举值补全的逻辑类似... return undefined; } }, // 触发字符当用户输入双引号时触发补全 );3.3 实现悬浮提示提供器 (HoverProvider)悬浮提示的逻辑相对直接在provideHover方法中获取光标所在位置的单词范围。判断这个单词是属性名还是枚举值。根据当前路径查询Schema找到对应的描述信息。用Markdown格式构造一个vscode.Hover对象返回。const hoverProvider vscode.languages.registerHoverProvider(myconfig, { provideHover(document, position) { const wordRange document.getWordRangeAtPosition(position, /[\\w\\.]/); if (!wordRange) { return null; } const word document.getText(wordRange); // 同样需要解析当前路径这里省略了解析代码 const currentPath parseJsonPath(document, position); let targetSchema schema; // ... 根据 currentPath 定位到具体的 schema 节点 // 假设定位到了最终的 propSchema if (propSchema propSchema.description) { const markdown new vscode.MarkdownString(); markdown.appendMarkdown(**${word}**\\n\\n); markdown.appendMarkdown(propSchema.description); if (propSchema.enum) { markdown.appendMarkdown(\\n\\n**Allowed values:** \\${propSchema.enum.join(, )}\\); } return new vscode.Hover(markdown); } return null; } });3.4 注册与订阅最后将创建的两个提供器加入到插件的订阅列表中以便在插件停用时自动清理。context.subscriptions.push(completionProvider, hoverProvider);我将Claude生成的代码复制到src/extension.ts并将之前定义好的Schema保存到schemas/myconfig-schema.json。然后运行npm run compile编译TypeScript再按F5启动一个扩展开发宿主Extension Development Host窗口进行测试。4. 调试、优化与生产级考量按下F5后一个新的VSCode窗口弹了出来。我创建了一个test.myconfig文件开始测试。基础功能运行得出乎意料的顺畅输入双引号后appName、version等属性名如约出现在补全列表中鼠标悬停在environment上也正确地显示了描述信息和枚举值。然而在更复杂的嵌套对象和边界情况下问题开始浮现。这也正是“生产级”调试的开始。4.1 遇到的第一个坑路径解析的健壮性Claude最初实现的parseJsonPath函数是一个简易版本。当我尝试在features: {}内部进行补全时它有时无法正确识别出当前路径是properties.features.properties导致补全列表为空。或者当JSON格式有轻微错误如缺少逗号时解析会直接失败。实操心得基于文本的、自制的JSON路径解析在复杂的编辑状态下是不可靠的。我向Claude反馈了这个问题“当前的路径解析逻辑在嵌套对象和格式错误时不稳定有没有更稳健的方法”Claude给出了一个更优的方案利用VSCode语言服务自带的jsonc-parserVSCode自己就在用这个库解析JSON和vscode-json-languageservice。后者是一个独立的库提供了完整的JSON解析、Schema校验和访问节点树的能力。我们更新了依赖并重写了路径解析逻辑import { parseTree, findNodeAtLocation, Node } from jsonc-parser; import { getLanguageService, DocumentLanguageService } from vscode-json-languageservice; const jsonLanguageService: DocumentLanguageService getLanguageService({}); // 在 provideCompletionItems 中 const documentText document.getText(); const rootNode: Node parseTree(documentText); // 使用 findNodeAtLocation 根据 position 偏移量找到精确的AST节点 // 再根据节点的父子关系推导出当前的JSON路径这种方法直接从AST抽象语法树层面获取位置信息完全避免了手动文本解析的种种陷阱鲁棒性大大提升。这是将插件质量从“玩具级”推向“可用级”的关键一步。4.2 性能与体验优化Schema缓存最初的实现每次触发补全或悬停都会重新读取和解析Schema文件。我让Claude将其改为在activate时加载并缓存到内存中避免了不必要的磁盘I/O。补全触发策略除了双引号我们还增加了在输入“: ”冒号空格后触发枚举值补全的逻辑使得在输入“environment”: “|”时能自动提示development、staging、production。错误处理在activate函数中增加了更完善的Schema加载错误处理不仅弹出错误提示还在控制台输出详细的堆栈信息便于调试。4.3 完善插件元信息一个正经的插件还需要一些“门面”工作。我让Claude补充了以下内容README.md说明插件的功能、使用方法和配置项。CHANGELOG.md记录版本更新日志。.vscodeignore指定在打包发布时需要忽略的文件如node_modules、*.ts源文件等。在package.json中完善了repository、keywords、engines指定兼容的VSCode版本等字段。最后运行vsce package命令成功生成了一个.vsix安装包文件。我可以在任何VSCode中通过“从VSIX安装”来加载这个插件它完全独立不需要连接任何外部AI服务。回顾这两个小时我的双手的确没有在核心业务逻辑上敲下一行代码。但我完成了更重要的几件事精准地定义问题、设计解决方案、指导开发AI实现、并进行测试和验收。Claude扮演了一个不知疲倦、能力全面的初级开发者快速将我的想法转化为可运行的代码。而我则必须拥有清晰的架构思维和调试能力去引导它、纠正它并将零散的代码模块组合成一个有机整体。这个实验证明对于模式清晰、边界明确的开发任务如为特定配置文件创建编辑器支持AI已经能极大地提升原型验证和基础实现的速度。它把开发者从繁琐的样板代码和API查阅中解放出来让我们能更专注于架构设计、体验优化和边界情况处理这些真正体现工程价值的地方。当然这并不意味着开发者会被取代相反对开发者理解问题、拆解问题、以及人机协作能力的要求变得更高了。
返回列表