比如我有这样一个 JSON
{
"pages": ["pages/index/index"],
"subpackages": [
{
"name": "A",
"pages": ["innerModule/pages/index/index"]
},
{
"name": "B",
"pages": ["innerModule/pages/index/index"]
}
]
}

需要实现一个函数找到 subpackages 下面 name === "xxx" 的 object ,然后替换当前的 object ,没有找到就 push 到 subpackages
使用 JSON.parse 很简单,但是会丢失格式信息,导致在 CI 中产生额外的 diff ,有什么很好处理这种场景的 AST 库推荐也行

预期的情况有两种:

  1. 当你需要改动的时候,一定会产生 diff
  2. 如果没有改动,则不能产生 diff

我的方案:直接用 JSON.parse/stringify 。你说的那种情况应该只有在原本的 JSON 字符串不是用 JSON.stringify 的情况下会产生。你可以先统一把已存在的文件全部重新格式化一遍,后续就不会产生 diff 。

key 排个序不就好了

我只想有改动的字段产生 diff ,因为一些流程的原因,没办法吧整个文件全部 parse 再 format 一遍

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#using_the_space_parameter

看看是不是你想要的

#4 链接错了,重发

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#specifications

他的锚点不好用,重发[笑哭]

console.log(JSON.stringify({ a: 2 }, null, " "));
/*
{
"a": 2
}
*/

console.log(JSON.stringify({ uno: 1, dos: 2 }, null, "\t"));
/*
{
"uno": 1,
"dos": 2
}
*/

先 parse => stringify , 现在的问题是在 pasre 处就丢失格式信息了

这种情况适合用 line parse 功能。

先把{"name": "A" .. }这个对象片段包含的连续行提取出来,别的行号内容都保留下来。

只序列化和反序列化这一小部分的文件内容,然后再拼装输出一个完整文件。相当于自己手动局部对象 JSON.parse/stringify ,而不是全局。

chatgpt 的答案能参考吗?
推荐使用 jsonc-parser 库,它可以解析带注释的 JSON ,然后根据需要更新 JSON 对象并生成新的 JSON string 。下面是一个示例代码,可以实现题目要求的功能:

const { parseTree, findNodeAtLocation, applyEdits, modify } = require("jsonc-parser");

function updatePackage(jsonStr, packageName, packageData) {
const ast = parseTree(jsonStr);
const subpackagesNode = findNodeAtLocation(ast, ["subpackages"]);
const packageIndex = subpackagesNode.children.findIndex(
(child) => findNodeAtLocation(child, ["value", "name"]).value === packageName
);
if (packageIndex !== -1) {
const packageNode = subpackagesNode.children[packageIndex];
const edits = modify(jsonStr, packageNode.offset, packageNode.length, JSON.stringify(packageData));
return applyEdits(jsonStr, edits);
} else {
const edits = modify(jsonStr, subpackagesNode.offset + subpackagesNode.length - 1, 0, ,${JSON.stringify(packageData)});
return applyEdits(jsonStr, edits);
}
}

const jsonStr = `{
"pages": ["pages/index/index"],
"subpackages": [
{
"name": "A",
"pages": ["innerModule/pages/index/index"]
},
{
"name": "B",
"pages": ["innerModule/pages/index/index"]
}
]
}`;

console.log(updatePackage(jsonStr, "C", { name: "C", pages: ["pages/C/index"] }));

在上面的代码中,updatePackage 函数接收一个 JSON string 、需要更新的包名和包数据。它首先使用 jsonc-parser 解析 JSON string ,然后在 AST 中查找 subpackages 节点。然后它在 subpackages 的子节点中查找与给定包名匹配的节点,如果找到了就将它替换为给定的包数据,否则就将包数据添加到 subpackages 的末尾。最后,它将生成的新 JSON string 返回。

由于使用 jsonc-parser 解析 JSON string 时可以保留格式信息,因此在 CI 中就不会产生额外的 diff 了。

#7 你好像没看懂我什么意思?你看#6 的代码,stringify 之前是没有格式的,加了后面的参数就有了格式。你手写的格式跟他一样就行了。

感谢,我试试这个代码,今天也用了 V 站上面免登录的 chatgpt ,问了半天也没问出你这样的结果,难道需要走什么流程

你试一下好吧,根本不需要什么库[笑哭]

console.log(JSON.stringify({uno:1,dos:[2,3],dns:{wf:{bbq:'5'},aec:4}}, null, "\t"))

{
"uno": 1,
"dos": [
2,
3
],
"dns": {
"wf": {
"bbq": "5"
},
"aec": 4
}
}

v2 把格式过滤掉了,发不出格式。

感谢你的热情,但是我不能把已有的 JSON 都格式化一遍,而且输入的 object 格式也不一定和原 JSON 一致,总结就是想达到就像手动编辑一样的 diff 效果

v2 支持 markdown ....

评论不支持

那我觉得你只能用正则写了,其他的插件也会有自己的格式,都有相同的问题。

#11 别人做的是第三方的,调用 api 的,api 的跟目前官方网页版不一样,一点都不智能一点都不好用。反正我试了基本很多答案都没法用,而官方网页版每次的回答都很智能很有针对性

实现了找到替换的功能,使用的库是 acorn(解析 ast 获取位置) 和 magic-string(更新字符)

gist.github.com/lisonge/51f6a7e6118a3412ecc226d20ea4fa0d