jsonc-parser, a fault tolerant scanner and parser for JSON with comments
Scanner and parser for JSON with comments.
At a glance
- What is it?
- microsoft/node-jsonc-parser is the TypeScript library behind VS Code's JSON with comments handling, offering a scanner, a SAX style visitor, a parse tree with offsets and editing APIs that compute edits rather than rewriting the document. It is published as ESM only, and a version 4 prerelease has been sitting around since June 2026.
- Who is it for?
- Adopt jsonc-parser if you need to read or rewrite JSON that carries JavaScript style comments, especially if you need to preserve formatting and report error positions. Skip it if your input is strict JSON with no comments, since a standard JSON.parse is enough.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The eight APIs and what each one is for
jsonc-parser is a scanner and fault tolerant parser for JSON with comments, described as JSON with JavaScript style comments. The README lists what the module provides, and the list is really a menu of levels of involvement.
The scanner tokenizes the input string into tokens and token offsets. The visit function implements a SAX style parser with callbacks for the properties and values encountered. The parseTree function computes a hierarchical DOM with offsets representing the properties and values. The parse function evaluates the JavaScript object the JSON string represents in a fault tolerant fashion.
Then there are the editing APIs. getLocation returns a location object describing the property or value at a given offset. findNodeAtLocation finds the node at a given location path in the JSON DOM. The format API computes edits to format a JSON document, and the modify API computes edits to insert, remove or replace a property or value. applyEdits applies edits to a document.
The distinction that matters most is between parse and parseTree. Parse gives you a value. ParseTree gives you a value plus the position of everything in it, and it is that tree that makes editing possible without losing the rest of the document.
The editing model is the clever part. Rather than serialising an object back to a string, which discards comments and formatting, the format and modify APIs return a list of edits, each a replacement over a byte range. You apply them to the original text. That is how a tool can add a setting to a configuration file that has comments in it without throwing the comments away.
The scanner interface and the fault tolerance contract
The scanner is created with createScanner, taking the text and an ignoreTrivia flag. The scanner object exposes setPosition to move to an offset, scan to read the next token and return its SyntaxKind, and a set of accessors describing the last token: getPosition, getToken, getTokenValue, getTokenOffset, getTokenLength, getTokenStartLine and getTokenStartCharacter, plus getTokenError for the error code of the last scan.
The line and character accessors are what make this usable in an editor. A token offset is a position in the string, but a diagnostic that says the problem is at offset 48213 is not useful to a person, whereas a line and column is.
The parse function takes the text, an optional array to collect errors into and an optional options object. The options are disallowComments, allowTrailingComma and allowEmptyContent.
The doc comment on parse states the contract plainly, and it is the single most important sentence in the README for anyone using this library. On invalid input, the parser tries to be as fault tolerant as possible, but still returns a result. Therefore always check the errors list to find out if the input was valid.
That is a deliberate design choice, and it is the right one for the editor use case. If a person is halfway through typing a configuration file, the editor wants to show them what it can parse so far and mark the broken part, rather than refusing to show anything. But it means parse never signals failure through its return value, and code that forgets to check the errors array will happily consume a half-parsed object as if it were valid.
The visitor callbacks follow the same philosophy, and they are all optional: onObjectBegin, onObjectProperty, onObjectEnd, onArrayBegin, onArrayEnd, onLiteralValue and onSeparator. Two of them can return false to stop descending, which is how you skip the contents of an array or object you are not interested in. The visitors also receive a pathSupplier, a function that returns the current JSONPath within the document.
ESM only, the export map and the package setup
The installation section is short and carries one important fact:
npm install --save jsonc-parserThe package is published as an ESM-only package. The package.json reflects that with type set to module and an exports map with a single dot entry that provides types pointing at lib/esm/main.d.ts and an import condition pointing at lib/esm/main.js.
There is no require condition and no default condition. That means a CommonJS consumer cannot load this package with require, and a bundler configured for CommonJS output will fail to resolve it. The migration path is straightforward if your project is ESM, and it is a real change if it is not.
The build is plain TypeScript. The compile script runs tsc against the src directory and then runs lint, the lint script runs eslint over the source, the clean script removes the lib directory with rimraf, and there is a watch script for tsc. The test script is worth noting, because it is a good pattern for a library without a test framework dependency: it compiles and then runs the Node built-in test runner directly against the compiled output.
npm run compile && node --enable-source-maps --test ./lib/esm/test/*.test.jsThe source maps flag means stack traces from the tests point at the TypeScript source rather than the compiled JavaScript, which is a small detail that saves time when a test fails.
The prepack script chains clean, compile, test and a remove-sourcemap-refs step, so the published package does not carry source map references. The devDependencies are minimal: TypeScript 5.8, eslint 9, the typescript-eslint plugin and parser, rimraf, and the Node types.
The repository root holds a src/ directory, a build/ directory with the helper scripts, an eslint config in .cjs form, a SECURITY.md, a CHANGELOG.md and a .vscode directory.
A prototype-pollution detail worth reading the source for
Among the exported functions the README documents, one stands out because it is named for the problem it solves rather than for what it does:
export declare function setObjectProperty(obj: Record<string, unknown>, key: string, value: unknown): void;The doc comment reads that it assigns value to obj[key], preserving __proto__ as an own data property without invoking the prototype setter.
That is prototype pollution handling. When you take a key from untrusted input and assign it onto a plain object with a plain assignment, a key of __proto__ can walk up the prototype chain and change the behaviour of every object in the process. The function exists so that a consumer who has to set an arbitrary key can do so without that risk, because it writes the property as an own data property rather than triggering the setter.
The presence of a dedicated exported helper for this tells you the maintainers have thought about it, and it is worth noticing that the ordinary parse function has the same exposure, since it evaluates a JSON document into JavaScript objects. If your document comes from an untrusted source, the safe path is the scanner and the visitor, which give you values without building objects.
That is a genuine architectural point rather than a detail: parse is convenient and parseTree or visit is safe, and the choice depends on where the input came from.
How this compares with JSON.parse and with the alternatives
The baseline comparison is with JSON.parse, which is fast, native, strict and has none of this library's features. For strict JSON, JSON.parse wins on every axis except error detail.
The interesting comparison is with the other approach to the same problem: strip the comments before parsing. That is what many tools do, with a regular expression or a hand-written stripper. The difference in approach shows up in the failure cases. A regular expression cannot reliably handle a comment marker inside a string, and a stripper that gets it wrong produces a parse error on a file that is perfectly valid JSONC.
Against the other JavaScript JSONC libraries, the distinguishing feature of jsonc-parser is that it is not only a parser. The editing APIs that compute edits rather than rewriting the text are the part that is hard to find elsewhere, and they are the part that makes it usable in an editor. There is also json5, which handles a superset of JSON with unquoted keys and other relaxations, and that is a different goal: jsonc-parser stays close to JSON and only adds comments.
The provenance is worth noting. This is the library Microsoft uses for JSON with comments in VS Code, and the package.json lists Microsoft Corporation as the author. That is a good sign for the maintenance of the format handling in the editor, though the repository is not a VS Code specific package and is usable on its own.
On the state of the project, the last stable release was v3.3.1 in June 2024, and there are two prereleases for version 4, v4.0.0-next.1 in March 2026 and v4.0.0-next.2 in June 2026, with the package.json sitting at 4.0.0-next.2. The last push was on 2026-10-19. The ESM-only change is the visible breaking change in that line, and if you are pinning, the stable 3.x line is the conservative choice.
Editorial conclusion
Adopt jsonc-parser if you need to read or rewrite JSON that carries JavaScript style comments, especially if you need to preserve formatting and report error positions. Skip it if your input is strict JSON with no comments, since a standard JSON.parse is enough. Verify first by checking the exports map in package.json for the ESM-only entry point, and confirm the errors array is checked after every parse call, because the parser is deliberately fault tolerant and returns a result even for invalid input.
Frequently asked questions
What does jsonc-parser provide?
A scanner that tokenizes text into tokens and offsets, a SAX style visit function with callbacks, a parseTree function computing a hierarchical DOM with offsets, a fault tolerant parse function, getLocation and findNodeAtLocation to locate nodes, and format, modify and applyEdits APIs that compute and apply text edits.
Is jsonc-parser still CommonJS compatible?
No. The package is published as ESM only, with type set to module and an exports map offering only an import condition. A CommonJS project cannot require it and needs to move to ESM or bundle it.
How do I know whether a jsonc-parser parse succeeded?
You check the errors array you passed in. The parser is deliberately fault tolerant and returns a result even for invalid input, so the doc comment says explicitly to always check the errors list to find out if the input was valid.
What is setObjectProperty for in jsonc-parser?
It assigns a value to obj[key] while preserving __proto__ as an own data property without invoking the prototype setter, which avoids prototype pollution when the key comes from untrusted input.
How does jsonc-parser edit a document without losing comments?
The format and modify APIs compute a list of edits over byte ranges of the original text rather than serialising an object back to a string, and applyEdits applies them. That keeps comments and the existing formatting intact.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/microsoft-node-jsonc-parser)Was this useful?