Comments (9)
@rekmarks I implemented this initially by simply re-using the existing isValidJson
utility function. This function does exactly what you suggested above.
I do however think it might be worth it to consider replacing it with something a bit more performant.
We could do something that looks more like this.
const VALID_JSON_TYPES = ['number', 'boolean', 'string'];
/**
* {@link Json} type guard.
*
* @param value - The value to check.
* @returns Whether the value is valid JSON.
*/
export function isValidJson(value: unknown): value is Json {
if (
value === null ||
value === undefined ||
VALID_JSON_TYPES.includes(typeof value)
) {
return true;
} else if (!isPlainObject(value) && !Array.isArray(value)) {
return false;
}
try {
const values = Object.values(value);
for (const nestedValue of values) {
if (!isValidJson(nestedValue)) {
return false;
}
}
} catch (_) {
return false;
}
return true;
}
We would then also need to replace current isPlainObject
utility function, which also currently seems to accept classes, weirdly?
For that we could do something like this.
export function isPlainObject(value: unknown): value is PlainObject {
if (typeof value !== 'object' || value === null) return false;
try {
let proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(value) === proto;
} catch (_) {
return false;
}
}
This approach is inspired by the way redux-toolkit does their detection of non-serializable objects.
See the following links:
https://github.com/reduxjs/redux-toolkit/blob/2ff1fa4364ce0dfa82dbbd3187aa0c63e57d5582/packages/toolkit/src/serializableStateInvariantMiddleware.ts#L35
from snaps.
That's a great suggestion @FrederikBolding.
Before we pursue a particular implementation, @shanejonas, have you or the OpenRPC folks by chance built anything that could be of help here?
from snaps.
My bad - didn't see you already approved the PR. Will merge now.
from snaps.
@rekmarks Based on our convo about possibly wanting to limit the size allowed for the JSON object I re-wrote my implementation to consider that too.
It's a lot less readable than the way we currently do things, but it is speedier. I compared to a simplified version here: https://jsben.ch/3VY6B - which it beats. And I assume with the deepEqual
check we currently do, this would be much faster.
export function getJsonSizing(value: unknown): [boolean, number] {
if (value === undefined) {
return [true, 0];
} else if (value === null) {
return [true, 4];
}
// eslint-disable-next-line default-case
switch (typeof value) {
case 'string':
// +2 for quotes
return [true, value.length + 2];
case 'boolean':
return [true, value ? 4 : 5];
case 'number':
return [true, value === 0 ? 1 : Math.floor(Math.log10(value) + 1)];
}
if (!isPlainObject(value) && !Array.isArray(value)) {
return [false, 0];
}
try {
// Starts at 2 because the string will minimally contain {}/[]
return [
true,
Object.entries(value).reduce((sum, [key, nestedValue], idx, arr) => {
const [valid, size] = getJsonSizing(nestedValue);
if (!valid) {
throw new Error();
}
// +3 "key":
const keySize = Array.isArray(value) ? 0 : key.length + 3;
const seperator = idx < arr.length - 1 ? 1 : 0;
return sum + keySize + size + seperator;
}, 2),
];
} catch (_) {
return [false, 0];
}
}
from snaps.
Suggested implementation (absent a try/catch):
if (!deepEqual(JSON.parse(JSON.stringify(snapState)), snapState)) throw Error('Invalid state');
On a related note, we may want to enforce some kind of maximum size for snap state, given by the length of the string. The above operation is less than cheap for large objects.
from snaps.
Also @FrederikBolding, if we end up pursuing your implementation, you might find this TypeScript Json
type test suite a helpful reference for the unit tests.
from snaps.
@rekmarks Definitely. Do you want to treat this suggestion as another PR and/or issue? Since the actual issue here should be solved by my already open PR.
from snaps.
That looks awesome. We should thoroughly document what this is doing in its docstring, but this looks pretty damn good.
from snaps.
@rekmarks I've assumed 1 byte per character for now, but we can make sure of that and/or check byte length of certain characters 👍 But yeah, we should add great documentation for this as well as a bunch of tests 😄
from snaps.
Related Issues (20)
- [TypeError: Cannot delete property 'dispose' of function Symbol() { [native code] }] HOT 2
- Environment variables missing nodeJS webpack plugin HOT 4
- Add wrappers for Snaps JSON-RPC
- Permitted error for snap invoking the other snap HOT 1
- Error for large image HOT 1
- Should we pass the installOrigin to the post-install hook? HOT 1
- Support for Starknet mainnet HOT 1
- Stability improvements
- Implement Snaps JSX components in extension
- Snap installation flow HOT 1
- Implement Chain API endowment
- Improve error message when trying to use top-level await
- Environement variable error: process is not defined HOT 2
- Stop crashing on lack of `onUserInput`
- Error for invoke-snap example HOT 1
- Invocation sequence for multiple transaction insight snaps HOT 1
- Investigate proxy execution environments failing to start
- wallet_requestSnaps always show install dialog in different localhost sites
- Make components clickable HOT 2
- Research: onClick handlers
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from snaps.