简易node ts代码给json进行sort或者diff

compare工具的问题在于,如果这些json的节点是未排序,导致基本上显示全部不同。
现node上几行代码,可以输出两个json的不同之处,也可以输出一个所有属性节点有序的json。

注意:这里数组元素也会以对象形式显现,数组的keys即为数组元素index。因为如果按数组处理,需要处理数组的元素是对象的情况,如果数组的元素是对象,那么排序规则是什么?(或者数组应该原样显示?,那么如果是字符串数组,难道不排序下?)
所以没有太完美的解决办法,反正我们的目的是比对和查找,不用于生产,那么代码统一处理带来的简洁可以弥补这点瑕疵。

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "strict": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictNullChecks": true,
    "allowJs": true,
    "checkJs": true,
    "removeComments": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "noImplicitOverride": true,
    "sourceMap": true,
    "declaration": true,
    "rootDir":"./src",
    "outDir":"./out",
    "experimentalDecorators": true,
    "watch":true
  },
  "include":[
    "./src/**/*"
  ],
  "exclude":[
//    "./src/test/*"
  ]
}

package.json

{
  "name": "json-sort-diff",
  "version": "1.0.0",
  "scripts": {
    "build": "tsc --build tsconfig.json"
  },
  "dependencies": {
    "@types/node": "^18.11.9"
  }
}

json-sort-diff.ts

const fs = require('fs');

(function main() {
    const argv = process.argv;
    // argv[0] ==> node
    // argv[1] ==> the js file

    if (argv.length == 3) {
        const json = fs.readFileSync(argv[2]);
        const obj = JSON.parse(json);
        console.log(JSON.stringify(orderedJson(obj), null, 2));
    } else if (argv.length === 4) {
        const fromJson = fs.readFileSync(argv[2]);
        const toJson = fs.readFileSync(argv[3]);
        const from = JSON.parse(fromJson);
        const to = JSON.parse(toJson);
        diff(from, to);
    } else {
        console.log("Examples:");
        console.log("1. Dump sorted json: node json-sort-diff.js path-of-json");
        console.log("2. Diff two json: node json-sort-diff.js path-of-from-json path-of-to-json")
        process.exit(0);
    }
})();

function orderedJson(unordered: any): any {
    return Object.keys(unordered).sort().reduce((obj: any, key: string) => {
        const value = unordered[key];
        if (typeof value === 'object') {
            obj[key] = orderedJson(value)
        } else {
            obj[key] = unordered[key];
        }
        return obj;
    }, {});
}

function dump(obj: any) {
    walk(obj, '', (path, key, value, leaf) => {
        if (leaf) {
            console.log(`${path} -> #(${value})`);
        } else {
            console.log(path);
        }
    });
}

function diff(from: any, to: any) {
    const noFounds: string[] = [];
    const diffInfos: DiffInfo[] = [];
    walk(from, '', (path, key, value, leaf) => {
        const segments = path.split('/');
        if (segments[0] === '') {
            segments.shift();
        }
        let current = to;
        for (const segment of segments) {
            if (current[segment] === undefined) {
                noFounds.push(path);
            }
            current = current[segment];
        }
        if (leaf) {
            if (current !== value) {
                diffInfos.push({ path, from: value, to: current })
            }
        }
    });
    console.log('\x1b[33m%s\x1b[0m', 'List of not found:');
    for (const noFound of noFounds.sort()) {
        console.log(noFound);
    }
    console.log('\x1b[33m%s\x1b[0m', 'List of different value:');
    for (const diffInfo of diffInfos.sort((a, b) => a.path.localeCompare(b.path))) {
        console.log(`${diffInfo.path} diff -> from:${diffInfo.from}; to:${diffInfo.to}`);
    }
}

export function walk(object: any, path: string, callback: (path: string, key: string, value: any, leaf: boolean) => void) {
    for (const [key, value] of Object.entries(object)) {
        const current = path + '/' + key;
        if (typeof value === 'object') {
            callback(current, key, value, false);
            walk(value, current, callback);
        } else {
            callback(current, key, value, true);
        }
    }
}

interface DiffInfo {
    path: string;
    from: any;
    to: any;
}

你可能感兴趣的:(json,javascript,前端)