Full Code of isaacs/json-stringify-safe for AI

master 5930d6e51c58 cached
10 files
12.5 KB
3.8k tokens
7 symbols
1 requests
Download .txt
Repository: isaacs/json-stringify-safe
Branch: master
Commit: 5930d6e51c58
Files: 10
Total size: 12.5 KB

Directory structure:
gitextract_dmgbmpss/

├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── package.json
├── stringify.js
└── test/
    ├── mocha.opts
    └── stringify_test.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/node_modules/
/*.tgz


================================================
FILE: .npmignore
================================================
/*.tgz


================================================
FILE: CHANGELOG.md
================================================
## 5.0.1 (May 19, 2015)
- Fixes stringify to only take ancestors into account when checking
  circularity.  
  It previously assumed every visited object was circular which led to [false
  positives][issue9].  
  Uses the tiny serializer I wrote for [Must.js][must] a year and a half ago.
- Fixes calling the `replacer` function in the proper context (`thisArg`).
- Fixes calling the `cycleReplacer` function in the proper context (`thisArg`).
- Speeds serializing by a factor of
  Big-O(h-my-god-it-linearly-searched-every-object) it had ever seen. Searching
  only the ancestors for a circular references speeds up things considerably.

[must]: https://github.com/moll/js-must
[issue9]: https://github.com/isaacs/json-stringify-safe/issues/9


================================================
FILE: LICENSE
================================================
The ISC License

Copyright (c) Isaac Z. Schlueter and Contributors

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


================================================
FILE: Makefile
================================================
NODE_OPTS =
TEST_OPTS =

love:
	@echo "Feel like makin' love."

test:
	@node $(NODE_OPTS) ./node_modules/.bin/_mocha -R dot $(TEST_OPTS)

spec:
	@node $(NODE_OPTS) ./node_modules/.bin/_mocha -R spec $(TEST_OPTS)

autotest:
	@node $(NODE_OPTS) ./node_modules/.bin/_mocha -R dot --watch $(TEST_OPTS)

autospec:
	@node $(NODE_OPTS) ./node_modules/.bin/_mocha -R spec --watch $(TEST_OPTS)

pack:
	@file=$$(npm pack); echo "$$file"; tar tf "$$file"

publish:
	npm publish

tag:
	git tag "v$$(node -e 'console.log(require("./package").version)')"

clean:
	rm -f *.tgz
	npm prune --production

.PHONY: love
.PHONY: test spec autotest autospec
.PHONY: pack publish tag
.PHONY: clean


================================================
FILE: README.md
================================================
# json-stringify-safe

Like JSON.stringify, but doesn't throw on circular references.

## Usage

Takes the same arguments as `JSON.stringify`.

```javascript
var stringify = require('json-stringify-safe');
var circularObj = {};
circularObj.circularRef = circularObj;
circularObj.list = [ circularObj, circularObj ];
console.log(stringify(circularObj, null, 2));
```

Output:

```json
{
  "circularRef": "[Circular]",
  "list": [
    "[Circular]",
    "[Circular]"
  ]
}
```

## Details

```
stringify(obj, serializer, indent, decycler)
```

The first three arguments are the same as to JSON.stringify.  The last
is an argument that's only used when the object has been seen already.

The default `decycler` function returns the string `'[Circular]'`.
If, for example, you pass in `function(k,v){}` (return nothing) then it
will prune cycles.  If you pass in `function(k,v){ return {foo: 'bar'}}`,
then cyclical objects will always be represented as `{"foo":"bar"}` in
the result.

```
stringify.getSerialize(serializer, decycler)
```

Returns a serializer that can be used elsewhere.  This is the actual
function that's passed to JSON.stringify.

**Note** that the function returned from `getSerialize` is stateful for now, so
do **not** use it more than once.


================================================
FILE: package.json
================================================
{
  "name": "json-stringify-safe",
  "version": "5.0.1",
  "description": "Like JSON.stringify, but doesn't blow up on circular refs.",
  "keywords": [
    "json",
    "stringify",
    "circular",
    "safe"
  ],
  "homepage": "https://github.com/isaacs/json-stringify-safe",
  "bugs": "https://github.com/isaacs/json-stringify-safe/issues",
  "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
  "contributors": [
    "Andri Möll <andri@dot.ee> (http://themoll.com)"
  ],
  "license": "ISC",
  "repository": {
    "type": "git",
    "url": "git://github.com/isaacs/json-stringify-safe"
  },
  "main": "stringify.js",
  "scripts": {
    "test": "make test"
  },
  "devDependencies": {
    "mocha": ">= 2.1.0 < 3",
    "must": ">= 0.12 < 0.13",
    "sinon": ">= 1.12.2 < 2"
  }
}


================================================
FILE: stringify.js
================================================
exports = module.exports = stringify
exports.getSerialize = serializer

function stringify(obj, replacer, spaces, cycleReplacer) {
  return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces)
}

function serializer(replacer, cycleReplacer) {
  var stack = [], keys = []

  if (cycleReplacer == null) cycleReplacer = function(key, value) {
    if (stack[0] === value) return "[Circular ~]"
    return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]"
  }

  return function(key, value) {
    if (stack.length > 0) {
      var thisPos = stack.indexOf(this)
      ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
      ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
      if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value)
    }
    else stack.push(value)

    return replacer == null ? value : replacer.call(this, key, value)
  }
}


================================================
FILE: test/mocha.opts
================================================
--recursive
--require must


================================================
FILE: test/stringify_test.js
================================================
var Sinon = require("sinon")
var stringify = require("..")
function jsonify(obj) { return JSON.stringify(obj, null, 2) }

describe("Stringify", function() {
  it("must stringify circular objects", function() {
    var obj = {name: "Alice"}
    obj.self = obj
    var json = stringify(obj, null, 2)
    json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
  })

  it("must stringify circular objects with intermediaries", function() {
    var obj = {name: "Alice"}
    obj.identity = {self: obj}
    var json = stringify(obj, null, 2)
    json.must.eql(jsonify({name: "Alice", identity: {self: "[Circular ~]"}}))
  })

  it("must stringify circular objects deeper", function() {
    var obj = {name: "Alice", child: {name: "Bob"}}
    obj.child.self = obj.child

    stringify(obj, null, 2).must.eql(jsonify({
      name: "Alice",
      child: {name: "Bob", self: "[Circular ~.child]"}
    }))
  })

  it("must stringify circular objects deeper with intermediaries", function() {
    var obj = {name: "Alice", child: {name: "Bob"}}
    obj.child.identity = {self: obj.child}

    stringify(obj, null, 2).must.eql(jsonify({
      name: "Alice",
      child: {name: "Bob", identity: {self: "[Circular ~.child]"}}
    }))
  })

  it("must stringify circular objects in an array", function() {
    var obj = {name: "Alice"}
    obj.self = [obj, obj]

    stringify(obj, null, 2).must.eql(jsonify({
      name: "Alice", self: ["[Circular ~]", "[Circular ~]"]
    }))
  })

  it("must stringify circular objects deeper in an array", function() {
    var obj = {name: "Alice", children: [{name: "Bob"}, {name: "Eve"}]}
    obj.children[0].self = obj.children[0]
    obj.children[1].self = obj.children[1]

    stringify(obj, null, 2).must.eql(jsonify({
      name: "Alice",
      children: [
        {name: "Bob", self: "[Circular ~.children.0]"},
        {name: "Eve", self: "[Circular ~.children.1]"}
      ]
    }))
  })

  it("must stringify circular arrays", function() {
    var obj = []
    obj.push(obj)
    obj.push(obj)
    var json = stringify(obj, null, 2)
    json.must.eql(jsonify(["[Circular ~]", "[Circular ~]"]))
  })

  it("must stringify circular arrays with intermediaries", function() {
    var obj = []
    obj.push({name: "Alice", self: obj})
    obj.push({name: "Bob", self: obj})

    stringify(obj, null, 2).must.eql(jsonify([
      {name: "Alice", self: "[Circular ~]"},
      {name: "Bob", self: "[Circular ~]"}
    ]))
  })

  it("must stringify repeated objects in objects", function() {
    var obj = {}
    var alice = {name: "Alice"}
    obj.alice1 = alice
    obj.alice2 = alice

    stringify(obj, null, 2).must.eql(jsonify({
      alice1: {name: "Alice"},
      alice2: {name: "Alice"}
    }))
  })

  it("must stringify repeated objects in arrays", function() {
    var alice = {name: "Alice"}
    var obj = [alice, alice]
    var json = stringify(obj, null, 2)
    json.must.eql(jsonify([{name: "Alice"}, {name: "Alice"}]))
  })

  it("must call given decycler and use its output", function() {
    var obj = {}
    obj.a = obj
    obj.b = obj

    var decycle = Sinon.spy(function() { return decycle.callCount })
    var json = stringify(obj, null, 2, decycle)
    json.must.eql(jsonify({a: 1, b: 2}, null, 2))

    decycle.callCount.must.equal(2)
    decycle.thisValues[0].must.equal(obj)
    decycle.args[0][0].must.equal("a")
    decycle.args[0][1].must.equal(obj)
    decycle.thisValues[1].must.equal(obj)
    decycle.args[1][0].must.equal("b")
    decycle.args[1][1].must.equal(obj)
  })

  it("must call replacer and use its output", function() {
    var obj = {name: "Alice", child: {name: "Bob"}}

    var replacer = Sinon.spy(bangString)
    var json = stringify(obj, replacer, 2)
    json.must.eql(jsonify({name: "Alice!", child: {name: "Bob!"}}))

    replacer.callCount.must.equal(4)
    replacer.args[0][0].must.equal("")
    replacer.args[0][1].must.equal(obj)
    replacer.thisValues[1].must.equal(obj)
    replacer.args[1][0].must.equal("name")
    replacer.args[1][1].must.equal("Alice")
    replacer.thisValues[2].must.equal(obj)
    replacer.args[2][0].must.equal("child")
    replacer.args[2][1].must.equal(obj.child)
    replacer.thisValues[3].must.equal(obj.child)
    replacer.args[3][0].must.equal("name")
    replacer.args[3][1].must.equal("Bob")
  })

  it("must call replacer after describing circular references", function() {
    var obj = {name: "Alice"}
    obj.self = obj

    var replacer = Sinon.spy(bangString)
    var json = stringify(obj, replacer, 2)
    json.must.eql(jsonify({name: "Alice!", self: "[Circular ~]!"}))

    replacer.callCount.must.equal(3)
    replacer.args[0][0].must.equal("")
    replacer.args[0][1].must.equal(obj)
    replacer.thisValues[1].must.equal(obj)
    replacer.args[1][0].must.equal("name")
    replacer.args[1][1].must.equal("Alice")
    replacer.thisValues[2].must.equal(obj)
    replacer.args[2][0].must.equal("self")
    replacer.args[2][1].must.equal("[Circular ~]")
  })

  it("must call given decycler and use its output for nested objects",
    function() {
    var obj = {}
    obj.a = obj
    obj.b = {self: obj}

    var decycle = Sinon.spy(function() { return decycle.callCount })
    var json = stringify(obj, null, 2, decycle)
    json.must.eql(jsonify({a: 1, b: {self: 2}}))

    decycle.callCount.must.equal(2)
    decycle.args[0][0].must.equal("a")
    decycle.args[0][1].must.equal(obj)
    decycle.args[1][0].must.equal("self")
    decycle.args[1][1].must.equal(obj)
  })

  it("must use decycler's output when it returned null", function() {
    var obj = {a: "b"}
    obj.self = obj
    obj.selves = [obj, obj]

    function decycle() { return null }
    stringify(obj, null, 2, decycle).must.eql(jsonify({
      a: "b",
      self: null,
      selves: [null, null]
    }))
  })

  it("must use decycler's output when it returned undefined", function() {
    var obj = {a: "b"}
    obj.self = obj
    obj.selves = [obj, obj]

    function decycle() {}
    stringify(obj, null, 2, decycle).must.eql(jsonify({
      a: "b",
      selves: [null, null]
    }))
  })

  it("must throw given a decycler that returns a cycle", function() {
    var obj = {}
    obj.self = obj
    var err
    function identity(key, value) { return value }
    try { stringify(obj, null, 2, identity) } catch (ex) { err = ex }
    err.must.be.an.instanceof(TypeError)
  })

  describe(".getSerialize", function() {
    it("must stringify circular objects", function() {
      var obj = {a: "b"}
      obj.circularRef = obj
      obj.list = [obj, obj]

      var json = JSON.stringify(obj, stringify.getSerialize(), 2)
      json.must.eql(jsonify({
        "a": "b",
        "circularRef": "[Circular ~]",
        "list": ["[Circular ~]", "[Circular ~]"]
      }))
    })

    // This is the behavior as of Mar 3, 2015.
    // The serializer function keeps state inside the returned function and
    // so far I'm not sure how to not do that. JSON.stringify's replacer is not
    // called _after_ serialization.
    xit("must return a function that could be called twice", function() {
      var obj = {name: "Alice"}
      obj.self = obj

      var json
      var serializer = stringify.getSerialize()

      json = JSON.stringify(obj, serializer, 2)
      json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))

      json = JSON.stringify(obj, serializer, 2)
      json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
    })
  })
})

function bangString(key, value) {
  return typeof value == "string" ? value + "!" : value
}
Download .txt
gitextract_dmgbmpss/

├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── package.json
├── stringify.js
└── test/
    ├── mocha.opts
    └── stringify_test.js
Download .txt
SYMBOL INDEX (7 symbols across 2 files)

FILE: stringify.js
  function stringify (line 4) | function stringify(obj, replacer, spaces, cycleReplacer) {
  function serializer (line 8) | function serializer(replacer, cycleReplacer) {

FILE: test/stringify_test.js
  function jsonify (line 3) | function jsonify(obj) { return JSON.stringify(obj, null, 2) }
  function decycle (line 181) | function decycle() { return null }
  function decycle (line 194) | function decycle() {}
  function identity (line 205) | function identity(key, value) { return value }
  function bangString (line 244) | function bangString(key, value) {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (14K chars).
[
  {
    "path": ".gitignore",
    "chars": 22,
    "preview": "/node_modules/\n/*.tgz\n"
  },
  {
    "path": ".npmignore",
    "chars": 7,
    "preview": "/*.tgz\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 744,
    "preview": "## 5.0.1 (May 19, 2015)\n- Fixes stringify to only take ancestors into account when checking\n  circularity.  \n  It previo"
  },
  {
    "path": "LICENSE",
    "chars": 765,
    "preview": "The ISC License\n\nCopyright (c) Isaac Z. Schlueter and Contributors\n\nPermission to use, copy, modify, and/or distribute t"
  },
  {
    "path": "Makefile",
    "chars": 675,
    "preview": "NODE_OPTS =\nTEST_OPTS =\n\nlove:\n\t@echo \"Feel like makin' love.\"\n\ntest:\n\t@node $(NODE_OPTS) ./node_modules/.bin/_mocha -R "
  },
  {
    "path": "README.md",
    "chars": 1261,
    "preview": "# json-stringify-safe\n\nLike JSON.stringify, but doesn't throw on circular references.\n\n## Usage\n\nTakes the same argument"
  },
  {
    "path": "package.json",
    "chars": 792,
    "preview": "{\n  \"name\": \"json-stringify-safe\",\n  \"version\": \"5.0.1\",\n  \"description\": \"Like JSON.stringify, but doesn't blow up on c"
  },
  {
    "path": "stringify.js",
    "chars": 907,
    "preview": "exports = module.exports = stringify\nexports.getSerialize = serializer\n\nfunction stringify(obj, replacer, spaces, cycleR"
  },
  {
    "path": "test/mocha.opts",
    "chars": 27,
    "preview": "--recursive\n--require must\n"
  },
  {
    "path": "test/stringify_test.js",
    "chars": 7550,
    "preview": "var Sinon = require(\"sinon\")\nvar stringify = require(\"..\")\nfunction jsonify(obj) { return JSON.stringify(obj, null, 2) }"
  }
]

About this extraction

This page contains the full source code of the isaacs/json-stringify-safe GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (12.5 KB), approximately 3.8k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!