From 70d73b09e243629cf5b5807517842186fae5c8de Mon Sep 17 00:00:00 2001 From: ItzNotABug Date: Sat, 27 Jul 2024 12:17:01 +0530 Subject: [PATCH 1/4] use: `json-bigint`. --- composer.lock | 86 ++++++++++++++++---------------- templates/web/package.json.twig | 4 ++ templates/web/src/client.ts.twig | 14 ++++-- templates/web/src/query.ts.twig | 10 ++-- 4 files changed, 63 insertions(+), 51 deletions(-) diff --git a/composer.lock b/composer.lock index 8910eeb81..2498e628a 100644 --- a/composer.lock +++ b/composer.lock @@ -1216,16 +1216,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.26", + "version": "10.5.28", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "42e2f13ceaa2e34461bc89bea75407550b40b2aa" + "reference": "ff7fb85cdf88131b83e721fb2a327b664dbed275" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/42e2f13ceaa2e34461bc89bea75407550b40b2aa", - "reference": "42e2f13ceaa2e34461bc89bea75407550b40b2aa", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ff7fb85cdf88131b83e721fb2a327b664dbed275", + "reference": "ff7fb85cdf88131b83e721fb2a327b664dbed275", "shasum": "" }, "require": { @@ -1235,26 +1235,26 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.5", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-invoker": "^4.0", - "phpunit/php-text-template": "^3.0", - "phpunit/php-timer": "^6.0", - "sebastian/cli-parser": "^2.0", - "sebastian/code-unit": "^2.0", - "sebastian/comparator": "^5.0", - "sebastian/diff": "^5.0", - "sebastian/environment": "^6.0", - "sebastian/exporter": "^5.1", - "sebastian/global-state": "^6.0.1", - "sebastian/object-enumerator": "^5.0", - "sebastian/recursion-context": "^5.0", - "sebastian/type": "^4.0", - "sebastian/version": "^4.0" + "phpunit/php-code-coverage": "^10.1.15", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.1", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -1297,7 +1297,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.26" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.28" }, "funding": [ { @@ -1313,7 +1313,7 @@ "type": "tidelift" } ], - "time": "2024-07-08T05:30:46+00:00" + "time": "2024-07-18T14:54:16+00:00" }, { "name": "psr/container", @@ -2366,16 +2366,16 @@ }, { "name": "symfony/console", - "version": "v7.1.2", + "version": "v7.1.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0aa29ca177f432ab68533432db0de059f39c92ae" + "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0aa29ca177f432ab68533432db0de059f39c92ae", - "reference": "0aa29ca177f432ab68533432db0de059f39c92ae", + "url": "https://api.github.com/repos/symfony/console/zipball/cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", + "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", "shasum": "" }, "require": { @@ -2439,7 +2439,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.2" + "source": "https://github.com/symfony/console/tree/v7.1.3" }, "funding": [ { @@ -2455,7 +2455,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-07-26T12:41:01+00:00" }, { "name": "symfony/deprecation-contracts", @@ -2685,16 +2685,16 @@ }, { "name": "symfony/process", - "version": "v7.1.1", + "version": "v7.1.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "febf90124323a093c7ee06fdb30e765ca3c20028" + "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028", - "reference": "febf90124323a093c7ee06fdb30e765ca3c20028", + "url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca", + "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca", "shasum": "" }, "require": { @@ -2726,7 +2726,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.1" + "source": "https://github.com/symfony/process/tree/v7.1.3" }, "funding": [ { @@ -2742,7 +2742,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-07-26T12:44:47+00:00" }, { "name": "symfony/service-contracts", @@ -2829,16 +2829,16 @@ }, { "name": "symfony/string", - "version": "v7.1.2", + "version": "v7.1.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8" + "reference": "ea272a882be7f20cad58d5d78c215001617b7f07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/14221089ac66cf82e3cf3d1c1da65de305587ff8", - "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8", + "url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07", + "reference": "ea272a882be7f20cad58d5d78c215001617b7f07", "shasum": "" }, "require": { @@ -2896,7 +2896,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.2" + "source": "https://github.com/symfony/string/tree/v7.1.3" }, "funding": [ { @@ -2912,7 +2912,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:27:18+00:00" + "time": "2024-07-22T10:25:37+00:00" }, { "name": "theseer/tokenizer", diff --git a/templates/web/package.json.twig b/templates/web/package.json.twig index e1e520353..f4b0f84c3 100644 --- a/templates/web/package.json.twig +++ b/templates/web/package.json.twig @@ -24,8 +24,12 @@ "build:types": "tsc --declaration --emitDeclarationOnly --outDir types", "build:libs": "rollup -c" }, + "dependencies": { + "json-bigint": "^1.0.0" + }, "devDependencies": { "@rollup/plugin-typescript": "8.3.2", + "@types/json-bigint": "^1.0.4", "playwright": "1.15.0", "rollup": "2.75.4", "serve-handler": "6.1.0", diff --git a/templates/web/src/client.ts.twig b/templates/web/src/client.ts.twig index 757b8ea98..ad37e61bf 100644 --- a/templates/web/src/client.ts.twig +++ b/templates/web/src/client.ts.twig @@ -1,5 +1,8 @@ import { Models } from './models'; import { Service } from './service'; +import JsonBigInt from 'json-bigint'; + +const jsonBigInt = JsonBigInt({ storeAsString: false }) /** * Payload type representing a key-value pair with string keys and any values. @@ -443,7 +446,7 @@ class Client { }, onMessage: (event) => { try { - const message: RealtimeResponse = JSON.parse(event.data); + const message: RealtimeResponse = jsonBigInt.parse(event.data); this.realtime.lastMessage = message; switch (message.type) { case 'connected': @@ -452,7 +455,7 @@ class Client { const messageData = message.data; if (session && !messageData.user) { - this.realtime.socket?.send(JSON.stringify({ + this.realtime.socket?.send(jsonBigInt.stringify({ type: 'authentication', data: { session @@ -579,7 +582,7 @@ class Client { } else { switch (headers['content-type']) { case 'application/json': - options.body = JSON.stringify(params); + options.body = jsonBigInt.stringify(params); break; case 'multipart/form-data': @@ -604,6 +607,7 @@ class Client { try { let data = null; const response = await fetch(url.toString(), options); + const responseData = await response.text() const warnings = response.headers.get('x-{{ spec.title | lower }}-warning'); if (warnings) { @@ -611,10 +615,10 @@ class Client { } if (response.headers.get('content-type')?.includes('application/json')) { - data = await response.json(); + data = jsonBigInt.parse(responseData) } else { data = { - message: await response.text() + message: responseData }; } diff --git a/templates/web/src/query.ts.twig b/templates/web/src/query.ts.twig index acad03823..7d040dd7b 100644 --- a/templates/web/src/query.ts.twig +++ b/templates/web/src/query.ts.twig @@ -1,8 +1,12 @@ +import JsonBigInt from 'json-bigint'; + type QueryTypesSingle = string | number | boolean; export type QueryTypesList = string[] | number[] | boolean[] | Query[]; export type QueryTypes = QueryTypesSingle | QueryTypesList; type AttributesTypes = string | string[]; +const jsonBigInt = JsonBigInt({ storeAsString: false }) + /** * Helper class to generate query strings. */ @@ -41,7 +45,7 @@ export class Query { * @returns {string} */ toString(): string { - return JSON.stringify({ + return jsonBigInt.stringify({ method: this.method, attribute: this.attribute, values: this.values, @@ -248,7 +252,7 @@ export class Query { * @returns {string} */ static or = (queries: string[]) => - new Query("or", undefined, queries.map((query) => JSON.parse(query))).toString(); + new Query("or", undefined, queries.map((query) => jsonBigInt.parse(query))).toString(); /** * Combine multiple queries using logical AND operator. @@ -257,5 +261,5 @@ export class Query { * @returns {string} */ static and = (queries: string[]) => - new Query("and", undefined, queries.map((query) => JSON.parse(query))).toString(); + new Query("and", undefined, queries.map((query) => jsonBigInt.parse(query))).toString(); } From cedc73f39d92342919c6cde2cace1cb22434e0af Mon Sep 17 00:00:00 2001 From: ItzNotABug Date: Sat, 27 Jul 2024 12:55:03 +0530 Subject: [PATCH 2/4] use: `json-bigint` for node as well. --- templates/node/package.json.twig | 2 ++ templates/node/src/client.ts.twig | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/templates/node/package.json.twig b/templates/node/package.json.twig index ca6435c13..82822ead3 100644 --- a/templates/node/package.json.twig +++ b/templates/node/package.json.twig @@ -42,12 +42,14 @@ }, "devDependencies": { "@types/node": "20.11.25", + "@types/json-bigint": "^1.0.4", "tsup": "7.2.0", "esbuild-plugin-file-path-extensions": "^2.0.0", "tslib": "2.6.2", "typescript": "5.4.2" }, "dependencies": { + "json-bigint": "^1.0.0", "node-fetch-native-with-agent": "1.7.2" } } diff --git a/templates/node/src/client.ts.twig b/templates/node/src/client.ts.twig index f7b12e5a7..b33522c70 100644 --- a/templates/node/src/client.ts.twig +++ b/templates/node/src/client.ts.twig @@ -1,6 +1,9 @@ import { fetch, FormData, File } from 'node-fetch-native-with-agent'; import { createAgent } from 'node-fetch-native-with-agent/agent'; import { Models } from './models'; +import JsonBigInt from 'json-bigint'; + +const jsonBigInt = JsonBigInt({ storeAsString: false }) type Payload = { [key: string]: any; @@ -170,7 +173,7 @@ class Client { } else { switch (headers['content-type']) { case 'application/json': - options.body = JSON.stringify(params); + options.body = jsonBigInt.stringify(params); break; case 'multipart/form-data': From 3656d3aa8d6ddf8dfe951a37c9126050c239f2bd Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 26 Nov 2024 19:11:24 +0530 Subject: [PATCH 3/4] update: use internal logic for `bigint`. --- src/SDK/Language/Node.php | 5 +++ src/SDK/Language/Web.php | 5 +++ templates/node/package.json.twig | 1 - templates/node/src/client.ts.twig | 6 ++-- templates/web/package.json.twig | 3 -- templates/web/src/client.ts.twig | 12 +++---- templates/web/src/helper/json.ts.twig | 46 +++++++++++++++++++++++++++ templates/web/src/query.ts.twig | 10 +++--- 8 files changed, 67 insertions(+), 21 deletions(-) create mode 100644 templates/web/src/helper/json.ts.twig diff --git a/src/SDK/Language/Node.php b/src/SDK/Language/Node.php index f7e819150..3f6754505 100644 --- a/src/SDK/Language/Node.php +++ b/src/SDK/Language/Node.php @@ -246,6 +246,11 @@ public function getFiles(): array 'destination' => 'src/enums/{{ enum.name | caseDash }}.ts', 'template' => 'web/src/enums/enum.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'src/helper/json.ts', + 'template' => 'web/src/helper/json.ts.twig', + ], ]; } } diff --git a/src/SDK/Language/Web.php b/src/SDK/Language/Web.php index 94b48343d..94776d3ba 100644 --- a/src/SDK/Language/Web.php +++ b/src/SDK/Language/Web.php @@ -120,6 +120,11 @@ public function getFiles(): array 'destination' => 'src/enums/{{ enum.name | caseDash }}.ts', 'template' => 'web/src/enums/enum.ts.twig', ], + [ + 'scope' => 'default', + 'destination' => 'src/helper/json.ts', + 'template' => 'web/src/helper/json.ts.twig', + ], ]; } diff --git a/templates/node/package.json.twig b/templates/node/package.json.twig index 82822ead3..4e45bc4e2 100644 --- a/templates/node/package.json.twig +++ b/templates/node/package.json.twig @@ -49,7 +49,6 @@ "typescript": "5.4.2" }, "dependencies": { - "json-bigint": "^1.0.0", "node-fetch-native-with-agent": "1.7.2" } } diff --git a/templates/node/src/client.ts.twig b/templates/node/src/client.ts.twig index a31e9432c..1982e17f9 100644 --- a/templates/node/src/client.ts.twig +++ b/templates/node/src/client.ts.twig @@ -1,9 +1,7 @@ import { fetch, FormData, File } from 'node-fetch-native-with-agent'; import { createAgent } from 'node-fetch-native-with-agent/agent'; import { Models } from './models'; -import JsonBigInt from 'json-bigint'; - -const jsonBigInt = JsonBigInt({ storeAsString: false }) +import JsonBigInt from './helper/json'; type Payload = { [key: string]: any; @@ -173,7 +171,7 @@ class Client { } else { switch (headers['content-type']) { case 'application/json': - options.body = jsonBigInt.stringify(params); + options.body = JsonBigInt.stringify(params); break; case 'multipart/form-data': diff --git a/templates/web/package.json.twig b/templates/web/package.json.twig index f4b0f84c3..33350e726 100644 --- a/templates/web/package.json.twig +++ b/templates/web/package.json.twig @@ -24,9 +24,6 @@ "build:types": "tsc --declaration --emitDeclarationOnly --outDir types", "build:libs": "rollup -c" }, - "dependencies": { - "json-bigint": "^1.0.0" - }, "devDependencies": { "@rollup/plugin-typescript": "8.3.2", "@types/json-bigint": "^1.0.4", diff --git a/templates/web/src/client.ts.twig b/templates/web/src/client.ts.twig index 09c43bc6b..55f77b494 100644 --- a/templates/web/src/client.ts.twig +++ b/templates/web/src/client.ts.twig @@ -1,7 +1,5 @@ import { Models } from './models'; -import JsonBigInt from 'json-bigint'; - -const jsonBigInt = JsonBigInt({ storeAsString: false }) +import JsonBigInt from './helper/json'; /** * Payload type representing a key-value pair with string keys and any values. @@ -445,7 +443,7 @@ class Client { }, onMessage: (event) => { try { - const message: RealtimeResponse = jsonBigInt.parse(event.data); + const message: RealtimeResponse = JsonBigInt.parse(event.data); this.realtime.lastMessage = message; switch (message.type) { case 'connected': @@ -454,7 +452,7 @@ class Client { const messageData = message.data; if (session && !messageData.user) { - this.realtime.socket?.send(jsonBigInt.stringify({ + this.realtime.socket?.send(JsonBigInt.stringify({ type: 'authentication', data: { session @@ -567,7 +565,7 @@ class Client { } else { switch (headers['content-type']) { case 'application/json': - options.body = jsonBigInt.stringify(params); + options.body = JsonBigInt.stringify(params); break; case 'multipart/form-data': @@ -655,7 +653,7 @@ class Client { } if (response.headers.get('content-type')?.includes('application/json')) { - data = jsonBigInt.parse(responseData) + data = JsonBigInt.parse(responseData) } else if (responseType === 'arrayBuffer') { data = await response.arrayBuffer(); } else { diff --git a/templates/web/src/helper/json.ts.twig b/templates/web/src/helper/json.ts.twig new file mode 100644 index 000000000..d611e3b0e --- /dev/null +++ b/templates/web/src/helper/json.ts.twig @@ -0,0 +1,46 @@ +/** + * Helper class for JSON parsing/stringifying with `BigInt` support. + */ +export default class JsonBigInt { + + // Preprocesses JSON to wrap large numbers in quotes. + static #preprocessJson(jsonString: string): string { + return jsonString.replaceAll( + /([:\s\[,]*)(-?\d+)([\s,\]]*)/g, + (match, prefix, num, suffix) => + !Number.isSafeInteger(+num) ? `${prefix}"${num}"${suffix}` : match + ); + } + + /** + * Parses JSON, converting large numbers to `BigInt`. + * + * @param {string} jsonString - The JSON string. + * @returns {any} - The parsed object. + */ + static parse(jsonString: string): any { + const processedJsonString = this.#preprocessJson(jsonString); + + return JSON.parse(processedJsonString, (key, value) => { + if (typeof value === 'string' && /^-?\d+$/.test(value)) { + return BigInt(value); + } + return value; + }); + } + + /** + * Stringifies an object, converting `BigInt` to strings. + * + * @param {object} obj - The object to stringify. + * @returns {string} - The JSON string. + */ + static stringify(obj: object): string { + return JSON.stringify(obj, (_, value) => { + if (typeof value === 'bigint') { + return value.toString(); + } + return value; + }); + } +} diff --git a/templates/web/src/query.ts.twig b/templates/web/src/query.ts.twig index 7d040dd7b..5736d02a0 100644 --- a/templates/web/src/query.ts.twig +++ b/templates/web/src/query.ts.twig @@ -1,12 +1,10 @@ -import JsonBigInt from 'json-bigint'; +import JsonBigInt from './helper/json'; type QueryTypesSingle = string | number | boolean; export type QueryTypesList = string[] | number[] | boolean[] | Query[]; export type QueryTypes = QueryTypesSingle | QueryTypesList; type AttributesTypes = string | string[]; -const jsonBigInt = JsonBigInt({ storeAsString: false }) - /** * Helper class to generate query strings. */ @@ -45,7 +43,7 @@ export class Query { * @returns {string} */ toString(): string { - return jsonBigInt.stringify({ + return JsonBigInt.stringify({ method: this.method, attribute: this.attribute, values: this.values, @@ -252,7 +250,7 @@ export class Query { * @returns {string} */ static or = (queries: string[]) => - new Query("or", undefined, queries.map((query) => jsonBigInt.parse(query))).toString(); + new Query("or", undefined, queries.map((query) => JsonBigInt.parse(query))).toString(); /** * Combine multiple queries using logical AND operator. @@ -261,5 +259,5 @@ export class Query { * @returns {string} */ static and = (queries: string[]) => - new Query("and", undefined, queries.map((query) => jsonBigInt.parse(query))).toString(); + new Query("and", undefined, queries.map((query) => JsonBigInt.parse(query))).toString(); } From bf00f1f5de3ab41aa242202602c77e462fd32a17 Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 26 Nov 2024 19:15:15 +0530 Subject: [PATCH 4/4] remove: types dependencies. --- templates/node/package.json.twig | 1 - templates/web/package.json.twig | 1 - 2 files changed, 2 deletions(-) diff --git a/templates/node/package.json.twig b/templates/node/package.json.twig index 4e45bc4e2..ca6435c13 100644 --- a/templates/node/package.json.twig +++ b/templates/node/package.json.twig @@ -42,7 +42,6 @@ }, "devDependencies": { "@types/node": "20.11.25", - "@types/json-bigint": "^1.0.4", "tsup": "7.2.0", "esbuild-plugin-file-path-extensions": "^2.0.0", "tslib": "2.6.2", diff --git a/templates/web/package.json.twig b/templates/web/package.json.twig index 33350e726..e1e520353 100644 --- a/templates/web/package.json.twig +++ b/templates/web/package.json.twig @@ -26,7 +26,6 @@ }, "devDependencies": { "@rollup/plugin-typescript": "8.3.2", - "@types/json-bigint": "^1.0.4", "playwright": "1.15.0", "rollup": "2.75.4", "serve-handler": "6.1.0",