Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ const libEntries: [string, string][] = [
["es2025.iterator", "lib.es2025.iterator.d.ts"],
["es2025.promise", "lib.es2025.promise.d.ts"],
["es2025.regexp", "lib.es2025.regexp.d.ts"],
["es2025.json", "lib.es2025.json.d.ts"],
// Fallback for backward compatibility
["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"],
["esnext.symbol", "lib.es2019.symbol.d.ts"],
Expand Down
1 change: 1 addition & 0 deletions src/lib/es2025.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/// <reference lib="es2025.iterator" />
/// <reference lib="es2025.promise" />
/// <reference lib="es2025.regexp" />
/// <reference lib="es2025.json" />
38 changes: 38 additions & 0 deletions src/lib/es2025.json.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Represents a "raw JSON" object created by `JSON.rawJSON()`.
*
* Raw JSON objects are frozen, null-prototype objects that carry pre-serialized
* JSON text. When encountered by `JSON.stringify()`, the `rawJSON` property
* value is emitted verbatim instead of the usual serialization.
*
* @see {@link https://tc39.es/proposal-json-parse-with-source/ TC39 proposal-json-parse-with-source}
*/
interface RawJSON {
readonly rawJSON: string;
}

interface JSON {
/**
* Converts a JavaScript Object Notation (JSON) string into an object.
* @param text A valid JSON string.
* @param reviver A function that transforms the results. This function is called for each member of the object.
* If a member contains nested objects, the nested objects are transformed before the parent object is.
* For each value, the reviver also receives a `context` object. When the property is unmodified and its value is
* primitive, `context` has a `source` property containing the original JSON text of that value.
*/
parse(text: string, reviver: (this: any, key: string, value: any, context: { source?: string }) => any): any;

/**
* Creates a "raw JSON" object containing a piece of JSON text.
* When serialized with `JSON.stringify()`, the raw text is emitted verbatim.
* @param text A valid JSON string representing a primitive value (string, number, boolean, or null).
* @throws {SyntaxError} If `text` is not valid JSON or represents an object or array.
*/
rawJSON(text: string): RawJSON;

/**
* Returns whether the provided value is a raw JSON object created by `JSON.rawJSON()`.
* @param value The value to test.
*/
isRawJSON(value: unknown): value is RawJSON;
}
1 change: 1 addition & 0 deletions src/lib/libs.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"es2025.iterator",
"es2025.promise",
"es2025.regexp",
"es2025.json",
"esnext.array",
"esnext.collection",
"esnext.date",
Expand Down
69 changes: 69 additions & 0 deletions tests/baselines/reference/jsonParseWithSource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//// [tests/cases/compiler/jsonParseWithSource.ts] ////

//// [jsonParseWithSource.ts]
// JSON.rawJSON
const raw = JSON.rawJSON("123");
const rawStr: string = raw.rawJSON;
JSON.stringify({ value: raw });
JSON.stringify({ n: JSON.rawJSON("12345678901234567890") });

// JSON.isRawJSON
const maybeRaw: unknown = {};
if (JSON.isRawJSON(maybeRaw)) {
const text: string = maybeRaw.rawJSON;
}

// JSON.parse with reviver context
// `source` is optional: only present for unmodified primitive values
JSON.parse('{"key":123}', (key, value, context) => {
const src: string | undefined = context.source;
return value;
});

// Test coverage for reviver context on array elements
JSON.parse('[1, 2, 3]', (key, value, context) => {
const src: string | undefined = context.source;
return value;
});

// Test coverage for reviver context on nested objects
JSON.parse('{"a": {"b": 1}}', (key, value, context) => {
const src: string | undefined = context.source;
return value;
});

// Existing JSON.parse overloads still work
JSON.parse("{}");
JSON.parse('{"a":1}', (key, value) => value);

//// [jsonParseWithSource.js]
"use strict";
// JSON.rawJSON
const raw = JSON.rawJSON("123");
const rawStr = raw.rawJSON;
JSON.stringify({ value: raw });
JSON.stringify({ n: JSON.rawJSON("12345678901234567890") });
// JSON.isRawJSON
const maybeRaw = {};
if (JSON.isRawJSON(maybeRaw)) {
const text = maybeRaw.rawJSON;
}
// JSON.parse with reviver context
// `source` is optional: only present for unmodified primitive values
JSON.parse('{"key":123}', (key, value, context) => {
const src = context.source;
return value;
});
// Test coverage for reviver context on array elements
JSON.parse('[1, 2, 3]', (key, value, context) => {
const src = context.source;
return value;
});
// Test coverage for reviver context on nested objects
JSON.parse('{"a": {"b": 1}}', (key, value, context) => {
const src = context.source;
return value;
});
// Existing JSON.parse overloads still work
JSON.parse("{}");
JSON.parse('{"a":1}', (key, value) => value);
124 changes: 124 additions & 0 deletions tests/baselines/reference/jsonParseWithSource.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//// [tests/cases/compiler/jsonParseWithSource.ts] ////

=== jsonParseWithSource.ts ===
// JSON.rawJSON
const raw = JSON.rawJSON("123");
>raw : Symbol(raw, Decl(jsonParseWithSource.ts, 1, 5))
>JSON.rawJSON : Symbol(JSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>rawJSON : Symbol(JSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))

const rawStr: string = raw.rawJSON;
>rawStr : Symbol(rawStr, Decl(jsonParseWithSource.ts, 2, 5))
>raw.rawJSON : Symbol(RawJSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))
>raw : Symbol(raw, Decl(jsonParseWithSource.ts, 1, 5))
>rawJSON : Symbol(RawJSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))

JSON.stringify({ value: raw });
>JSON.stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>value : Symbol(value, Decl(jsonParseWithSource.ts, 3, 16))
>raw : Symbol(raw, Decl(jsonParseWithSource.ts, 1, 5))

JSON.stringify({ n: JSON.rawJSON("12345678901234567890") });
>JSON.stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>n : Symbol(n, Decl(jsonParseWithSource.ts, 4, 16))
>JSON.rawJSON : Symbol(JSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>rawJSON : Symbol(JSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))

// JSON.isRawJSON
const maybeRaw: unknown = {};
>maybeRaw : Symbol(maybeRaw, Decl(jsonParseWithSource.ts, 7, 5))

if (JSON.isRawJSON(maybeRaw)) {
>JSON.isRawJSON : Symbol(JSON.isRawJSON, Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>isRawJSON : Symbol(JSON.isRawJSON, Decl(lib.es2025.json.d.ts, --, --))
>maybeRaw : Symbol(maybeRaw, Decl(jsonParseWithSource.ts, 7, 5))

const text: string = maybeRaw.rawJSON;
>text : Symbol(text, Decl(jsonParseWithSource.ts, 9, 9))
>maybeRaw.rawJSON : Symbol(RawJSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))
>maybeRaw : Symbol(maybeRaw, Decl(jsonParseWithSource.ts, 7, 5))
>rawJSON : Symbol(RawJSON.rawJSON, Decl(lib.es2025.json.d.ts, --, --))
}

// JSON.parse with reviver context
// `source` is optional: only present for unmodified primitive values
JSON.parse('{"key":123}', (key, value, context) => {
>JSON.parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>key : Symbol(key, Decl(jsonParseWithSource.ts, 14, 27))
>value : Symbol(value, Decl(jsonParseWithSource.ts, 14, 31))
>context : Symbol(context, Decl(jsonParseWithSource.ts, 14, 38))

const src: string | undefined = context.source;
>src : Symbol(src, Decl(jsonParseWithSource.ts, 15, 9))
>context.source : Symbol(source, Decl(lib.es2025.json.d.ts, --, --))
>context : Symbol(context, Decl(jsonParseWithSource.ts, 14, 38))
>source : Symbol(source, Decl(lib.es2025.json.d.ts, --, --))

return value;
>value : Symbol(value, Decl(jsonParseWithSource.ts, 14, 31))

});

// Test coverage for reviver context on array elements
JSON.parse('[1, 2, 3]', (key, value, context) => {
>JSON.parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>key : Symbol(key, Decl(jsonParseWithSource.ts, 20, 25))
>value : Symbol(value, Decl(jsonParseWithSource.ts, 20, 29))
>context : Symbol(context, Decl(jsonParseWithSource.ts, 20, 36))

const src: string | undefined = context.source;
>src : Symbol(src, Decl(jsonParseWithSource.ts, 21, 9))
>context.source : Symbol(source, Decl(lib.es2025.json.d.ts, --, --))
>context : Symbol(context, Decl(jsonParseWithSource.ts, 20, 36))
>source : Symbol(source, Decl(lib.es2025.json.d.ts, --, --))

return value;
>value : Symbol(value, Decl(jsonParseWithSource.ts, 20, 29))

});

// Test coverage for reviver context on nested objects
JSON.parse('{"a": {"b": 1}}', (key, value, context) => {
>JSON.parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>key : Symbol(key, Decl(jsonParseWithSource.ts, 26, 31))
>value : Symbol(value, Decl(jsonParseWithSource.ts, 26, 35))
>context : Symbol(context, Decl(jsonParseWithSource.ts, 26, 42))

const src: string | undefined = context.source;
>src : Symbol(src, Decl(jsonParseWithSource.ts, 27, 9))
>context.source : Symbol(source, Decl(lib.es2025.json.d.ts, --, --))
>context : Symbol(context, Decl(jsonParseWithSource.ts, 26, 42))
>source : Symbol(source, Decl(lib.es2025.json.d.ts, --, --))

return value;
>value : Symbol(value, Decl(jsonParseWithSource.ts, 26, 35))

});

// Existing JSON.parse overloads still work
JSON.parse("{}");
>JSON.parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))

JSON.parse('{"a":1}', (key, value) => value);
>JSON.parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>JSON : Symbol(JSON, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>parse : Symbol(JSON.parse, Decl(lib.es5.d.ts, --, --), Decl(lib.es2025.json.d.ts, --, --))
>key : Symbol(key, Decl(jsonParseWithSource.ts, 33, 23))
>value : Symbol(value, Decl(jsonParseWithSource.ts, 33, 27))
>value : Symbol(value, Decl(jsonParseWithSource.ts, 33, 27))

Loading