Modify JSON strings with a fluent chainable API while preserving formatting, comments, and whitespace.
- π¨ Format Preservation - Maintains comments, whitespace, and original formatting
- π Chainable API - Fluent interface for readable modifications
- β‘ Sequential Operations - Apply multiple changes in order
- π Fast & Lightweight - Zero dependencies, minimal footprint
- π¦ Dual module support - Works with both ESM and CommonJS
- πͺ TypeScript Support - Full type definitions included
- π― Flexible Path Syntax - Supports both dot notation and JSON Pointer
npm install json-codemodOr using other package managers:
yarn add json-codemod
# or
pnpm add json-codemodimport jsonmod from "json-codemod";
const source = '{"name": "Alice", "age": 30, "items": [1, 2, 3]}';
const result = jsonmod(source)
.replace("name", '"Bob"')
.replace("age", "31")
.delete("items[1]")
.insert("items", 2, "4")
.apply();
// Result: {"name": "Bob", "age": 31, "items": [1, 4, 3]}Use formatValue for automatic type handling:
import jsonmod, { formatValue } from "json-codemod";
const source = '{"name": "Alice", "age": 30, "active": false}';
const result = jsonmod(source)
.replace("name", formatValue("Bob")) // Strings quoted automatically
.replace("age", formatValue(31)) // Numbers handled correctly
.replace("active", formatValue(true)) // Booleans too
.apply();
// Result: {"name": "Bob", "age": 31, "active": true}Creates a chainable instance for JSON modifications.
Parameters:
sourceText(string): JSON string to modify
Returns: JsonMod instance
Example:
const mod = jsonmod('{"name": "Alice"}');Replace a value at the specified path.
Parameters:
path(string | string[]): JSON pathvalue(string): New value as JSON string
Returns: this (chainable)
Examples:
// Simple replacement
jsonmod(source).replace("name", '"Bob"').apply();
// Nested path
jsonmod(source).replace("user.profile.age", "31").apply();
// Array element
jsonmod(source).replace("items[1]", "99").apply();
// Using formatValue
jsonmod(source).replace("name", formatValue("Bob")).apply();Delete a property or array element.
Parameters:
path(string | string[]): JSON path
Returns: this (chainable)
Examples:
// Delete property
jsonmod(source).delete("age").apply();
// Delete array element
jsonmod(source).delete("items[0]").apply();
// Delete nested property
jsonmod(source).delete("user.email").apply();
// Multiple deletions (remove is alias)
jsonmod(source)
.delete("a")
.remove("b")
.apply();Insert into objects or arrays.
Parameters:
path(string | string[]): Path to containerkeyOrPosition(string | number): Property name (object) or index (array)value(string): Value as JSON string
Returns: this (chainable)
Examples:
// Insert into object
jsonmod(source)
.insert("", "email", '"[email protected]"')
.apply();
// Insert into array at position
jsonmod(source)
.insert("items", 0, '"first"')
.apply();
// Append to array
jsonmod(source)
.insert("items", 3, '"last"')
.apply();
// Using formatValue
jsonmod(source)
.insert("user", "age", formatValue(30))
.apply();Execute all queued operations and return modified JSON.
Returns: Modified JSON string
Example:
const result = jsonmod(source)
.replace("a", "1")
.delete("b")
.insert("", "c", "3")
.apply(); // Execute and return resultConvert JavaScript values to JSON strings automatically.
Parameters:
value(any): JavaScript value
Returns: JSON string representation
Examples:
import { formatValue } from "json-codemod";
formatValue(42) // "42"
formatValue("hello") // '"hello"'
formatValue(true) // "true"
formatValue(null) // "null"
formatValue({a: 1}) // '{"a":1}'
formatValue([1, 2, 3]) // '[1,2,3]'import jsonmod, { formatValue } from "json-codemod";
import { readFileSync, writeFileSync } from "fs";
const config = readFileSync("tsconfig.json", "utf-8");
const updated = jsonmod(config)
.replace("compilerOptions.target", formatValue("ES2022"))
.replace("compilerOptions.strict", formatValue(true))
.delete("compilerOptions.experimentalDecorators")
.insert("compilerOptions", "moduleResolution", formatValue("bundler"))
.apply();
writeFileSync("tsconfig.json", updated);const source = `{
// User configuration
"name": "Alice",
"age": 30, /* years */
"active": true
}`;
const result = jsonmod(source)
.replace("age", "31")
.replace("active", "false")
.apply();
// Comments and formatting preserved!const data = '{"user": {"name": "Alice", "settings": {"theme": "dark"}}}';
const result = jsonmod(data)
.replace("user.name", formatValue("Bob"))
.replace("user.settings.theme", formatValue("light"))
.insert("user.settings", "language", formatValue("en"))
.apply();const source = '{"items": [1, 2, 3, 4, 5]}';
const result = jsonmod(source)
.delete("items[1]") // Remove second item
.delete("items[2]") // Remove what is now third item
.insert("items", 0, "0") // Insert at beginning
.apply();
// Result: {"items": [0, 1, 4, 5]}let mod = jsonmod(config);
if (isDevelopment) {
mod = mod.replace("debug", "true");
}
if (needsUpdate) {
mod = mod.replace("version", formatValue("2.0.0"));
}
const result = mod.apply();jsonmod(source).replace("user.profile.name", '"Bob"').apply();jsonmod(source).replace("items[0]", "1").apply();
jsonmod(source).delete("items[2]").apply();jsonmod(source).replace("/user/profile/name", '"Bob"').apply();For keys with special characters, use JSON Pointer:
// Key with slash: "a/b"
jsonmod(source).replace("/a~1b", "value").apply();
// Key with tilde: "a~b"
jsonmod(source).replace("/a~0b", "value").apply();Full TypeScript support with type definitions:
import jsonmod, { JsonMod, formatValue } from "json-codemod";
const source = '{"name": "Alice", "age": 30}';
const instance: JsonMod = jsonmod(source);
const result: string = instance
.replace("name", formatValue("Bob"))
.delete("age")
.apply();- Parse: Creates a Concrete Syntax Tree (CST) preserving all formatting
- Queue: Operations are queued, not executed immediately
- Execute:
.apply()runs operations sequentially, re-parsing after each - Return: Returns the modified JSON string with formatting preserved
Without formatValue:
.replace("name", '"Bob"') // Must remember quotes
.replace("age", "30") // No quotes for numbers
.replace("active", "true") // No quotes for booleansWith formatValue:
.replace("name", formatValue("Bob")) // Automatic
.replace("age", formatValue(30)) // Automatic
.replace("active", formatValue(true)) // AutomaticThe library parses JSON into a Concrete Syntax Tree that includes comments and whitespace as tokens. Modifications only change value tokens, leaving everything else intact.
Operations are applied sequentially with re-parsing between each. This ensures correctness but means:
- Fast for small to medium JSON files
- For large files with many operations, consider batching similar changes
No, call .apply() returns a string and operations are cleared. Create a new instance for new modifications:
const result1 = jsonmod(source).replace("a", "1").apply();
const result2 = jsonmod(result1).replace("b", "2").apply();Contributions are welcome! Please feel free to submit a Pull Request.