Merge 177791ae5d03fa80f2dcc433dfa86bd2d95b688f into 2a1294f1c089bb8e68d38d1803d08858907f352a

This commit is contained in:
Mao Jun 2025-08-08 10:27:29 +00:00 committed by GitHub
commit ef8698b2c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 236 additions and 0 deletions

10
package-lock.json generated
View File

@ -58,6 +58,7 @@
"json5": "^2.2.3", "json5": "^2.2.3",
"jsonata": "^2.0.3", "jsonata": "^2.0.3",
"jsonpath-plus": "^9.0.0", "jsonpath-plus": "^9.0.0",
"jsonrepair": "^3.13.0",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "8.5.1",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"jsrsasign": "^11.1.0", "jsrsasign": "^11.1.0",
@ -12520,6 +12521,15 @@
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/jsonrepair": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/jsonrepair/-/jsonrepair-3.13.0.tgz",
"integrity": "sha512-5YRzlAQ7tuzV1nAJu3LvDlrKtBFIALHN2+a+I1MGJCt3ldRDBF/bZuvIPzae8Epot6KBXd0awRZZcuoeAsZ/mw==",
"license": "ISC",
"bin": {
"jsonrepair": "bin/cli.js"
}
},
"node_modules/jsonwebtoken": { "node_modules/jsonwebtoken": {
"version": "8.5.1", "version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",

View File

@ -144,6 +144,7 @@
"json5": "^2.2.3", "json5": "^2.2.3",
"jsonata": "^2.0.3", "jsonata": "^2.0.3",
"jsonpath-plus": "^9.0.0", "jsonpath-plus": "^9.0.0",
"jsonrepair": "^3.13.0",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "8.5.1",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"jsrsasign": "^11.1.0", "jsrsasign": "^11.1.0",

View File

@ -465,6 +465,7 @@
"JavaScript Minify", "JavaScript Minify",
"JSON Beautify", "JSON Beautify",
"JSON Minify", "JSON Minify",
"JSON Repair",
"XML Beautify", "XML Beautify",
"XML Minify", "XML Minify",
"SQL Beautify", "SQL Beautify",

View File

@ -0,0 +1,48 @@
/**
* @author maojunxyz [maojun@linux.com]
* @copyright Crown Copyright 2025
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
import Operation from "../Operation.mjs";
/**
* JSON Repair operation
*/
class JSONRepair extends Operation {
/**
* JSONRepair constructor
*/
constructor() {
super();
this.name = "JSON Repair";
this.module = "Code";
this.description = "Attempts to repair invalid JSON by fixing common issues such as missing quotes around keys, trailing commas, single quotes, missing brackets, and more.<br><br>This operation can fix:<br>• Missing quotes around keys<br>• Single quotes instead of double quotes<br>• Trailing commas<br>• Missing commas<br>• Missing closing brackets<br>• Python constants (None, True, False)<br>• Comments<br>• JSONP notation<br>• And many other common JSON formatting issues<br><br>Uses the jsonrepair library for comprehensive JSON repair.<br><br>Tags: json fix, json repair, json validate, json format";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
if (!input) return "";
try {
// Dynamic import of jsonrepair to handle potential module loading issues
const { jsonrepair } = await import("jsonrepair");
return jsonrepair(input);
} catch (err) {
throw new OperationError("Unable to repair JSON. The input contains errors that cannot be automatically fixed.\n" + err.message);
}
}
}
export default JSONRepair;

View File

@ -93,6 +93,7 @@ import "./tests/JA3SFingerprint.mjs";
import "./tests/Jsonata.mjs"; import "./tests/Jsonata.mjs";
import "./tests/JSONBeautify.mjs"; import "./tests/JSONBeautify.mjs";
import "./tests/JSONMinify.mjs"; import "./tests/JSONMinify.mjs";
import "./tests/JSONRepair.mjs";
import "./tests/JSONtoCSV.mjs"; import "./tests/JSONtoCSV.mjs";
import "./tests/Jump.mjs"; import "./tests/Jump.mjs";
import "./tests/JWK.mjs"; import "./tests/JWK.mjs";

View File

@ -0,0 +1,175 @@
/**
* JSONRepair tests.
*
* @author maojunxyz [maojun@linux.com]
*
* @copyright Crown Copyright 2025
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "JSON Repair: empty string",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: valid JSON unchanged",
input: "{\"name\": \"John\", \"age\": 30}",
expectedOutput: "{\"name\": \"John\", \"age\": 30}",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: missing quotes around keys",
input: "{name: \"John\", age: 30}",
expectedOutput: "{\"name\": \"John\", \"age\": 30}",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: single quotes to double quotes",
input: "{'name': 'John', 'age': 30}",
expectedOutput: "{\"name\": \"John\", \"age\": 30}",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: trailing comma in object",
input: "{\"name\": \"John\", \"age\": 30,}",
expectedOutput: "{\"name\": \"John\", \"age\": 30}",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: trailing comma in array",
input: "[1, 2, 3,]",
expectedOutput: "[1, 2, 3]",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: Python constants",
input: "{\"active\": True, \"data\": None, \"flag\": False}",
expectedOutput: "{\"active\": true, \"data\": null, \"flag\": false}",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: line comments",
input: `{
"name": "John", // This is a comment
"age": 30
}`,
expectedOutput: `{
"name": "John",
"age": 30
}`,
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: block comments",
input: `{
"name": "John", /* This is a
multi-line comment */
"age": 30
}`,
expectedOutput: `{
"name": "John",
"age": 30
}`,
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: missing comma",
input: `{
"name": "John"
"age": 30,
"city": "Boston"
}`,
expectedOutput: `{
"name": "John",
"age": 30,
"city": "Boston"
}`,
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: complex mixed issues",
input: `{
name: "John", // Person's name
age: 30,
active: True,
data: None,
}`,
expectedOutput: `{
"name": "John",
"age": 30,
"active": true,
"data": null
}`,
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
{
name: "JSON Repair: JSONP notation",
input: "callback({\"name\": \"John\", \"age\": 30})",
expectedOutput: "{\"name\": \"John\", \"age\": 30}",
recipeConfig: [
{
op: "JSON Repair",
args: [],
},
],
},
]);