Skip to content

Commit 899a882

Browse files
committed
Add fromJs function
1 parent 0dd5629 commit 899a882

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

src/json/jsonast-util.d.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@ export type Reviver<A> = (node: JsonCompatible<NonNullable<A>>, key?: string) =>
1616
* Parse a JSON string into a JSON AST. Includes a reviver option similar to
1717
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse | JSON.parse}.
1818
*
19-
* @throws SynatxError
19+
* @throws SynataxError
2020
*/
2121
export const fromJson: <A = JsonNode>(json: string, reviver?: Reviver<A>) => A;
2222

23+
/**
24+
* Parse a JSON compatible JavaScript value into a JSON AST.
25+
*/
26+
export const fromJs: (js: Json) => JsonNode;
27+
2328
export type Replacer<A = JsonNode> = (node: A, key?: string) => JsonCompatible<A> | undefined;
2429

2530
/**

src/json/jsonast-util.js

+72
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,78 @@ const tokenPosition = (startToken, endToken) => {
174174
};
175175
};
176176

177+
/** @type API.fromJs */
178+
export const fromJs = (js) => {
179+
switch (typeof js) {
180+
case "boolean":
181+
return {
182+
type: "json",
183+
jsonType: "boolean",
184+
value: js
185+
};
186+
187+
case "number":
188+
return {
189+
type: "json",
190+
jsonType: "number",
191+
value: js
192+
};
193+
194+
case "string":
195+
return {
196+
type: "json",
197+
jsonType: "string",
198+
value: js
199+
};
200+
201+
case "object":
202+
if (js === null) {
203+
return {
204+
type: "json",
205+
jsonType: "null",
206+
value: js
207+
};
208+
}
209+
210+
if (Array.isArray(js)) {
211+
return {
212+
type: "json",
213+
jsonType: "array",
214+
children: js.map(fromJs)
215+
};
216+
}
217+
218+
if (Object.getPrototypeOf(js) === Object.prototype) {
219+
/** @type JsonPropertyNode[] */
220+
const properties = [];
221+
for (const key in js) {
222+
properties.push({
223+
type: "json-property",
224+
children: [
225+
{
226+
type: "json-property-name",
227+
value: key
228+
},
229+
fromJs(js[key])
230+
]
231+
});
232+
}
233+
234+
return {
235+
type: "json",
236+
jsonType: "object",
237+
children: properties
238+
};
239+
}
240+
241+
const type = js.constructor?.name ?? "*anonymous*";
242+
throw TypeError(`Not a JSON compatible type: ${type}`);
243+
244+
default:
245+
throw TypeError(`Not a JSON compatible type: ${typeof js}`);
246+
}
247+
};
248+
177249
/**
178250
* @template [A = JsonNode]
179251
* @typedef {(node: A, key?: string) => JsonCompatible<A> | undefined} Replacer

0 commit comments

Comments
 (0)