Avatar

@freecrayon

3 likes6 public vals
Joined May 24, 2023

JSON.parse and JSON.stringify that preserves BigInt values.

Works by encoding BigInt values into strings with a special prefix.

See https://www.val.town/v/freecrayon/JSONBigInt_example for an example of how to use it.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const prefix = "BIGINT::";
const prefixLength = prefix.length;
const stringify = (data: unknown, _?: null, padding?: number): string => {
return JSON.stringify(
data,
(_key, value) => (typeof value === "bigint" ? `${prefix}${value}` : value),
padding,
);
};
const parse = (data: string): unknown => {
return JSON.parse(data, (_key, value) => {
if (typeof value === "string" && value.startsWith(prefix)) {
return BigInt(value.slice(prefixLength));
}
return value;
});
};
export { parse, stringify };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { fetch } from "https://esm.town/v/std/fetch";
export default async function(request: Request): Promise<Response> {
const url = new URL(request.url);
const query = url.searchParams.get("query") ?? "";
const cheerio = await import("https://esm.sh/cheerio@1.0.0-rc.12");
const response = await fetch(
"https://launchpad.net/~git-core/+archive/ubuntu/ppa/+packages",
);
const body = await response.text();
const $ = cheerio.load(body);
const rowText = [...$(".archive_package_row a")].map((el) => {
return $(el).text();
}).find((row) => {
return !query || row.includes(query);
});
const matchVersion = /^\s*git\s*-\s*(.+)/.exec(rowText);
if (!matchVersion) {
throw new Error(
`Could not extract version from page. Trying to parse "${rowText}"`,
);
}
const version = matchVersion[1];
return new Response(JSON.stringify({ query, version }));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { fetch } from "https://esm.town/v/std/fetch";
export default async function(request: Request): Promise<Response> {
const cheerio = await import("https://esm.sh/cheerio@1.0.0-rc.12");
const response = await fetch("https://releases.1password.com/linux/beta/");
const body = await response.text();
const $ = cheerio.load(body);
const heading = $(".c-page-details div").first().text();
const matchVersion = /^Updated to ([\d.-]+)/.exec(heading);
if (!matchVersion) {
throw new Error("Could not extract version from page");
}
const version = matchVersion[1];
return new Response(JSON.stringify({ version }));
}

It's like Array.prototype.map but for the Map, allowing you to transform keys and values.

Readme
1
2
3
4
5
6
7
8
9
10
const mapMap = <Key, ValueIn, ValueOut>(
map: Map<Key, ValueIn>,
fn: (value: ValueIn, key: Key, index: number) => ValueOut,
): Map<Key, ValueOut> => {
return new Map(
[...map].map(([key, value], index) => [key, fn(value, key, index)]),
);
};
export { mapMap };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { zodStringToJSON } from "https://esm.town/v/freecrayon/zodStringToJSON";
import { zfd } from "npm:zod-form-data";
const $CommentFormData = zfd.formData({
commentId: zfd.text(),
content: zfd.text(zodStringToJSON()),
});
// usually this will be passed to you by your Server (i.e. SvelteKit, Remix)
const formData = new FormData();
formData.set("commentId", "abc123");
formData.set("content", `{"hello":"world","value":12}`);
const { commentId, content } = $CommentFormData.parse(formData);
console.log({ commentId, content });

Useful when working with ZodFormData and you need to parse a text field that contains JSON.

See https://www.val.town/v/freecrayon/zodStringToJSON_example for an example of how to use it.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
import { z } from "npm:zod";
const zodStringToJSON = () =>
z.string().transform((str, ctx): z.infer<z.ZodType<unknown>> => {
try {
return JSON.parse(str);
} catch (e) {
ctx.addIssue({ code: "custom", message: "Invalid JSON" });
return z.NEVER;
}
});
export { zodStringToJSON };
Next