当前状态
我们在几个地方进行JSON验证/反序列化。
验证可能会失败,需要插入错误消息、默认值,通常还会提供一个JSON模式。
以下是我们目前如何实现的一些示例:
- 语言配置
- 验证:
vscode/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts
第167行 0f4df3d
| | if(!Array.isArray(source)){ |
- JSON模式:
vscode/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts
第545行 0f4df3d
| | brackets: { |
- 默认值?
- 编辑器设置
- TypeScript类型定义:
vscode/src/vs/editor/common/config/editorOptions.ts
第2535行 0f4df3d
| | side?: 'right'|'left'; |
- 验证:
vscode/src/vs/editor/common/config/editorOptions.ts
第2637行 0f4df3d
| | side: stringSet<'right'|'left'>(input.side,this.defaultValue.side,['right','left']), |
- 默认值:
vscode/src/vs/editor/common/config/editorOptions.ts
第2570行 0f4df3d
| | side: 'right', |
- JSON模式:
vscode/src/vs/editor/common/config/editorOptions.ts
第2595行 0f4df3d
| | 'editor.minimap.side': { |
- 在命令中处理
args
的处理过程
问题
当前进行JSON反序列化/验证的方式非常冗长且不一致。
没有保证JSON模式与验证相匹配(尽管有时这是有意为之的)。
建议解决方案
我建议探索引入一个通用的、描述性的反序列化辅助程序,允许在单个地方指定TypeScript类型、验证逻辑、默认值和人类可读的描述。可以从那里派生出JSON模式。
结果应该是一个内部辅助程序(而不是外部库),类似于io-ts或我自己的库hediet/semantic-json(示例)。
在editor.minimap.side
的情况下,代码应该如下所示:
const editorMinimap = objectDeserializer({
properties: {
...
side: property(enumDeserializer(['left', 'right']), {
defaultValue: 'left',
description: nls.localize('minimap.side', "Controls the side where to render the minimap.")
})
...
}
});
const editorSettings = objectDeserializer({
properties: {
...
minimap: editorMinimap
...
}
});
assert.deepStrictEqual(flatten(objectDeserializer({ properties: { editor: editorSettings } })).getJSONSchema(), {
...
"editor.minimap.side": {
type: 'string',
enum: ['left', 'right'],
default: 'left',
description: "Controls the side where to render the minimap."
...
}
...
});
对此感兴趣的人可能是:
@alexdima@connor4312@aeschli
如果对此有兴趣进一步探讨,我很乐意进一步研究这个想法。
6条答案
按热度按时间vuktfyat1#
我也在使用方法2为LSIF生成验证器。请参阅https://github.com/microsoft/lsif-node/blob/fd6a872b17da1fc05029271445c76aae70e35fc6/protocol/src/protocol.ts#L171-L171
slhcrj9b2#
总的来说,我认为我们应该探索代码生成。所有的设置都可以用一个或多个JSON文件(可能使用JSON schema或JSON schema++)来描述,然后可以生成类型定义(带有漂亮的JSDoc注解)或高效的类型验证代码。但这需要在团队中讨论并达成一致。
从编辑器选项的Angular 来看,我非常希望看到一个明确的提案,解决以下问题:
monaco.d.ts
中通过JSDoc注解提供,因为这是编辑器嵌入者最终编译的代码。我们有时也会从我们的代码库示例化编辑器(例如REPL编辑器),我们需要在那里进行类型验证。updateOptions
的情况下,选项必须高效地计算updateOptions
应最终创建一个可查询的选项更改事件,该事件针对已更改的选项。svmlkihl3#
如果我们采用代码生成的方法来解决 .d.ts 问题,我会投票支持简单地使用 JSON schema。实际上,在构建服务 API 之前,我曾经这样做过,并且非常喜欢它——将 JSON schema 作为事实依据和验证输入的方式,并从中推导出类型。此外,JSON schema 周围有许多现有的工具。
此外,虽然这个设计关注于设置,但与此相关的、可能可以用相同的工具链解决的问题是扩展主机通信。目前,与扩展主机进行的通信主要通过 JSON 序列化完成,并附带一些特殊处理。正如我在 #133200 中提到的,我们当前在这里拥有的抽象是有漏洞的,即使不偏离 JSON,也可能存在 benefits ,提前了解序列化数据的形状。如果我们使用一个为协议类型提供运行时信息系统,就有机会改进。
j7dteeu84#
我喜欢这个想法。我认为
@hediet/semantic-json
,我在这次迭代的早期ssh工作中使用了很多次,非常适合需求——我们不能将其用作外部库而不是内部库吗?显然有些东西需要扩展,但这似乎是一件可以重复利用的事情。io-ts似乎更笨重,第一眼我就不太喜欢它的API。
fd3cxomn5#
我们能否将其用作外部库而非内部库?显然有些东西需要扩展,但这似乎可以重用。
我建议复制@hediet/semantic-json的设计并将其适应VS Code的具体需求。我在工作中使用个人库时感到不太舒服;)
我喜欢VS Code不使用许多库,而且我们可以轻松更改实用程序。
io-ts似乎更庞大,第一眼我就不喜欢它的API。
这就是为什么我从semantic-json开始的原因。io-ts类型在运行时也无法反映,这是生成json-schema所必需的。
f5emj3cl6#
@dbaeumer指出了一个重要问题:TypeScript在d.ts文件中生成的类型是什么样的?
有两种方法。
方法1:定义反序列化器,推断TypeScript类型(如hediet/semantic-json和io-ts所使用的)
生成的类型:
方法2:显式定义TypeScript类型,强制匹配反序列化器
生成的类型:
TypeScript Playground链接
我认为由于缺少JS Docs(我们需要用于编辑器选项),只有方法2是可行的。