JSNT

JSNT

Lightweight static utility library for working with JSON data in vanilla JavaScript — read, query, transform, convert, and cache objects.

Usage
<script src="/dist/jsnt.min.js"></script>

No setup — every helper is a static method on the global jsnt object, plus the jsnt.date and jsnt.cache sub-namespaces.

const posts = {
    1: { title: 'First',  views: 30 },
    2: { title: 'Second', views: 90 },
}

jsnt.sum(posts, 'views')     // → 120
jsnt.sort(posts, 'views')    // → posts ordered by views
jsnt.flatten({ a: { b: 1 } }) // → { 'a.b': 1 }

Core

Reading JSON from strings, URLs, and objects, and writing it back out.

parse
await jsnt.parse(data)  // → object | null

Resolves data to an object. A string starting with http is fetched and parsed; any other string is parsed with JSON.parse; an object is returned as-is. Returns null and logs on error.

ParamTypeDescription
data required string | object A URL, a JSON string, or an object.
await jsnt.parse('{"a":1}')                 // → { a: 1 }
await jsnt.parse('https://api.site/data.json') // fetch + parse
await jsnt.parse({ a: 1 })                   // → { a: 1 }
get
await jsnt.get(url, callback)

Fetches a JSON file and passes the parsed object to callback. Throws on a non-2xx response or a parse error.

await jsnt.get('/config.json', config => {
    console.log(config.version)
})
download
await jsnt.download(filename, content?)

Triggers a browser download. When content is omitted, filename is fetched first and its body is saved.

jsnt.download('user.json', jsnt.toString({ id: 1 }))
jsnt.download('/remote.json')  // fetch, then save under the same name
replace
await jsnt.replace(url, key, value)  // → object

Fetches a JSON file, sets one top-level key to value, and returns the updated object. Throws if any argument is missing.

const updated = await jsnt.replace('/user.json', 'active', true)

Read & write

Reach into and edit objects by key or dot-path.

set
jsnt.set(obj, path, value)

Sets a value at a dot-separated path, mutating obj in place. Missing intermediate objects are created automatically.

const user = {}
jsnt.set(user, 'profile.name', 'Ada')
// user → { profile: { name: 'Ada' } }
has
jsnt.has(obj, path)  // → boolean

Returns true if the dot-separated path exists on obj.

jsnt.has({ profile: { name: 'Ada' } }, 'profile.name')  // → true
jsnt.has({ profile: {} }, 'profile.age')                // → false
remove
jsnt.remove(obj, key)  // → object

Deletes a top-level key and returns the object. A JSON string is parsed first.

jsnt.remove({ a: 1, b: 2 }, 'b')  // → { a: 1 }
renameKey
jsnt.renameKey(obj, oldKey, newKey)  // → object

Returns a copy of obj with one key renamed. Returns the object unchanged if oldKey is absent.

jsnt.renameKey({ name: 'Ada' }, 'name', 'fullName')  // → { fullName: 'Ada' }

Query

Inspect, filter, sort, and compare objects.

keys
jsnt.keys(obj)  // → string[]

Top-level keys of the object.

count
jsnt.count(obj)  // → number

Number of top-level keys.

isEmpty
jsnt.isEmpty(obj)  // → boolean

Returns true when the object has no own keys.

filter
jsnt.filter(obj, condition)  // → object

Keeps entries whose value satisfies condition(value), preserving keys.

const users = { 1: { age: 30 }, 2: { age: 12 } }
jsnt.filter(users, u => u.age >= 18)  // → { 1: { age: 30 } }
sort
jsnt.sort(obj, key)  // → object

Returns a new object with entries ordered by the numeric value[key], ascending.

const posts = { a: { views: 90 }, b: { views: 30 } }
jsnt.sort(posts, 'views')  // → { b: { views: 30 }, a: { views: 90 } }
equal
jsnt.equal(a, b)  // → boolean

Deep equality — recurses through objects and arrays comparing keys and values.

jsnt.equal({ a: [1, 2] }, { a: [1, 2] })  // → true
jsnt.equal({ a: 1 }, { a: 1, b: 2 })      // → false

Transform

Reshape objects and arrays.

merge
jsnt.merge(...objects)  // → object

Shallow-merges any number of objects left to right — later keys win.

jsnt.merge({ a: 1 }, { b: 2 }, { a: 3 })  // → { a: 3, b: 2 }
flatten
jsnt.flatten(obj)  // → object

Flattens a nested object into a single level with dot-path keys.

jsnt.flatten({ a: { b: { c: 1 } }, d: 2 })
// → { 'a.b.c': 1, d: 2 }
map
jsnt.map(obj, callback)  // → object | array

Recursively applies callback to every leaf value, keeping the object/array shape.

jsnt.map({ a: 1, b: { c: 2 } }, v => v * 10)
// → { a: 10, b: { c: 20 } }
group
jsnt.group(array, key)  // → object

Groups an array of objects into buckets keyed by the value of key.

jsnt.group([{ type: 'a', n: 1 }, { type: 'b', n: 2 }, { type: 'a', n: 3 }], 'type')
// → { a: [ {…n:1}, {…n:3} ], b: [ {…n:2} ] }
toArray
jsnt.toArray(obj)  // → array

The object's values as an array (Object.values).

jsnt.toArray({ a: 1, b: 2 })  // → [1, 2]

Aggregate

Reduce a keyed collection to a single number.

sum
jsnt.sum(obj, key)  // → number

Sums value[key] across all values of the object.

jsnt.sum({ 1: { views: 30 }, 2: { views: 90 } }, 'views')  // → 120
average
jsnt.average(obj, key)  // → number

Average of value[key] across all values.

jsnt.average({ 1: { views: 30 }, 2: { views: 90 } }, 'views')  // → 60

Serialize

Convert between objects and JSON, YAML, and XML.

toString
jsnt.toString(obj)  // → string

JSON.stringify shorthand.

toJson
jsnt.toJson(string)  // → object

JSON.parse shorthand.

toYAML
jsnt.toYAML(obj)  // → string

Serializes an object to YAML, indenting nested objects by two spaces.

jsnt.toYAML({ app: { name: 'Yurba', port: 80 } })
// app:
//   name: Yurba
//   port: 80
parseYAML
jsnt.parseYAML(string)  // → object

Parses flat key: value YAML into an object. Blank lines and # comments are skipped.

jsnt.parseYAML('name: Yurba\nport: 80')  // → { name: 'Yurba', port: '80' }
toXML
jsnt.toXML(obj)  // → string

Serializes an object to an XML string wrapped in a <root> element.

jsnt.toXML({ user: { name: 'Ada' } })
// → <root><user><name>Ada</name></user></root>
parseXML
jsnt.parseXML(string)  // → object

Parses an XML string into a nested object. Repeated sibling tags collapse into an array.

jsnt.parseXML('<root><name>Ada</name></root>')  // → { name: 'Ada' }
validate
jsnt.validate(obj)  // → boolean

Returns true if the value round-trips through JSON.stringify / JSON.parse — i.e. it is JSON-serializable.

Dates

Work with unix timestamps in seconds via the jsnt.date namespace.

date.convert
jsnt.date.convert(unix, format, timeZone?)  // → string

Formats a unix timestamp. Tokens: DD, MM, YYYY, hh, mm, ss.

jsnt.date.convert(1700000000, 'DD.MM.YYYY hh:mm')  // → '14.11.2023 22:13'
date.diff
jsnt.date.diff(a, b, unit?)  // → number | object

Difference between two timestamps. With a unit (years, months, days, hours, minutes, seconds, milliseconds) returns that number; without one, returns an object of all units.

jsnt.date.diff(now, now - 3600, 'minutes')  // → 60
date.now
jsnt.date.now()  // → number

Current unix timestamp in seconds.

date.add
jsnt.date.add(unix, parts)  // → number

Adds a duration to a timestamp. parts accepts years, months, days, hours, minutes, seconds (each defaults to 0).

jsnt.date.add(jsnt.date.now(), { days: 7, hours: 12 })
date.substr
jsnt.date.substr(unix, parts)  // → number

Subtracts a duration from a timestamp. Same parts shape as date.add.

jsnt.date.substr(jsnt.date.now(), { months: 1 })

Cache

A simple in-memory key–value store on the jsnt.cache namespace. Values live for the lifetime of the page.

cache.new
jsnt.cache.new(key, value)

Stores (or overwrites) a value under key.

jsnt.cache.new('user', { id: 1, name: 'Ada' })
cache.add
jsnt.cache.add(key, value)

Merges value into an existing entry. Works whether the stored entry is an object or a JSON string.

jsnt.cache.add('user', { role: 'admin' })  // → { id: 1, name: 'Ada', role: 'admin' }
cache.get
jsnt.cache.get(key)  // → any

Reads the value stored under key.

cache.remove
jsnt.cache.remove(key)

Deletes a single cache entry.

cache.clear
jsnt.cache.clear()

Empties the entire cache.