From 5ed19c6c3c6e7a1bacde8c23c438ecb85454b126 Mon Sep 17 00:00:00 2001 From: Steven Luscher Date: Wed, 17 Apr 2024 00:38:47 -0700 Subject: [PATCH] Add types to `@solana/fast-stable-stringify` (#2502) This thing returns a string always, unless you pass it `undefined` or a function. --- .changeset/brave-chicken-own.md | 5 +++++ packages/fast-stable-stringify/package.json | 2 ++ .../src/__typetests__/index-typetest.ts | 20 +++++++++++++++++ packages/fast-stable-stringify/src/index.ts | 22 ++++++++++++------- .../tsconfig.declarations.json | 10 +++++++++ packages/rpc-graphql/src/loaders/loader.ts | 5 +---- 6 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 .changeset/brave-chicken-own.md create mode 100644 packages/fast-stable-stringify/src/__typetests__/index-typetest.ts create mode 100644 packages/fast-stable-stringify/tsconfig.declarations.json diff --git a/.changeset/brave-chicken-own.md b/.changeset/brave-chicken-own.md new file mode 100644 index 000000000000..bca1c52b1349 --- /dev/null +++ b/.changeset/brave-chicken-own.md @@ -0,0 +1,5 @@ +--- +"@solana/fast-stable-stringify": patch +--- + +Added TypeScript types to `@solana/fast-stable-stringify` diff --git a/packages/fast-stable-stringify/package.json b/packages/fast-stable-stringify/package.json index 6f9948ccd4ef..d558120a524b 100644 --- a/packages/fast-stable-stringify/package.json +++ b/packages/fast-stable-stringify/package.json @@ -37,6 +37,7 @@ ], "scripts": { "compile:js": "tsup --config build-scripts/tsup.config.package.ts", + "compile:typedefs": "tsc -p ./tsconfig.declarations.json && node ../../node_modules/@solana/build-scripts/add-js-extension-to-types.mjs", "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch", "prepublishOnly": "pnpm pkg delete devDependencies", "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag ${PUBLISH_TAG:-preview} --access public --no-git-checks", @@ -47,6 +48,7 @@ "test:treeshakability:browser": "agadoo dist/index.browser.js", "test:treeshakability:native": "agadoo dist/index.native.js", "test:treeshakability:node": "agadoo dist/index.node.js", + "test:typecheck": "tsc --noEmit", "test:unit:browser": "jest -c ../../node_modules/@solana/test-config/jest-unit.config.browser.ts --rootDir . --silent", "test:unit:node": "jest -c ../../node_modules/@solana/test-config/jest-unit.config.node.ts --rootDir . --silent" }, diff --git a/packages/fast-stable-stringify/src/__typetests__/index-typetest.ts b/packages/fast-stable-stringify/src/__typetests__/index-typetest.ts new file mode 100644 index 000000000000..2f22062fb110 --- /dev/null +++ b/packages/fast-stable-stringify/src/__typetests__/index-typetest.ts @@ -0,0 +1,20 @@ +import fastStableStringify from '../index'; + +fastStableStringify(undefined) satisfies undefined; +fastStableStringify(function () {}) satisfies undefined; +fastStableStringify(() => {}) satisfies undefined; +fastStableStringify(class Foo {}) satisfies undefined; + +fastStableStringify({ UNDEFINED: undefined }) satisfies string; +fastStableStringify({ foo: 'bar' }) satisfies string; +fastStableStringify([1, 2, 3]) satisfies string; +fastStableStringify(1n) satisfies string; +fastStableStringify(BigInt(1)) satisfies string; +fastStableStringify(1) satisfies string; +fastStableStringify(5e-324) satisfies string; +fastStableStringify(0xdeadbeef) satisfies string; +fastStableStringify(true) satisfies string; +fastStableStringify(false) satisfies string; +fastStableStringify('string') satisfies string; +fastStableStringify(new Date()) satisfies string; +fastStableStringify(null) satisfies string; diff --git a/packages/fast-stable-stringify/src/index.ts b/packages/fast-stable-stringify/src/index.ts index e421bd7c4af0..fd2b9bed55f8 100644 --- a/packages/fast-stable-stringify/src/index.ts +++ b/packages/fast-stable-stringify/src/index.ts @@ -9,7 +9,7 @@ const objKeys = return keys; }; -function stringify(val, isArrayProp) { +function stringify(val: unknown, isArrayProp: boolean) { let i, max, str, keys, key, propVal, toStr; if (val === true) { return 'true'; @@ -21,18 +21,18 @@ function stringify(val, isArrayProp) { case 'object': if (val === null) { return null; - } else if (val.toJSON && typeof val.toJSON === 'function') { + } else if ('toJSON' in val && typeof val.toJSON === 'function') { return stringify(val.toJSON(), isArrayProp); } else { toStr = objToString.call(val); if (toStr === '[object Array]') { str = '['; - max = val.length - 1; + max = (val as unknown[]).length - 1; for (i = 0; i < max; i++) { - str += stringify(val[i], true) + ','; + str += stringify((val as unknown[])[i], true) + ','; } if (max > -1) { - str += stringify(val[i], true); + str += stringify((val as unknown[])[i], true); } return str + ']'; } else if (toStr === '[object Object]') { @@ -43,7 +43,7 @@ function stringify(val, isArrayProp) { i = 0; while (i < max) { key = keys[i]; - propVal = stringify(val[key], false); + propVal = stringify((val as Record)[key], false); if (propVal !== undefined) { if (str) { str += ','; @@ -65,11 +65,17 @@ function stringify(val, isArrayProp) { case 'string': return JSON.stringify(val); default: - return isFinite(val) ? val : null; + return isFinite(val as number) ? val : null; } } -export default function (val) { +export default function ( + val: + | Function // eslint-disable-line @typescript-eslint/ban-types + | undefined, +): undefined; +export default function (val: unknown): string; +export default function (val: unknown): string | undefined { const returnVal = stringify(val, false); if (returnVal !== undefined) { return '' + returnVal; diff --git a/packages/fast-stable-stringify/tsconfig.declarations.json b/packages/fast-stable-stringify/tsconfig.declarations.json new file mode 100644 index 000000000000..dc2d27bb09ff --- /dev/null +++ b/packages/fast-stable-stringify/tsconfig.declarations.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "./dist/types" + }, + "extends": "./tsconfig.json", + "include": ["src/index.ts", "src/types"] +} diff --git a/packages/rpc-graphql/src/loaders/loader.ts b/packages/rpc-graphql/src/loaders/loader.ts index 2a1ee30bd09d..1371dc3f1376 100644 --- a/packages/rpc-graphql/src/loaders/loader.ts +++ b/packages/rpc-graphql/src/loaders/loader.ts @@ -1,6 +1,4 @@ import type { Address } from '@solana/addresses'; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore import stringify from '@solana/fast-stable-stringify'; import type { Signature } from '@solana/keys'; import type { GetAccountInfoApi, GetBlockApi, GetProgramAccountsApi, GetTransactionApi } from '@solana/rpc'; @@ -67,5 +65,4 @@ export type RpcGraphQLLoaders = { transaction: TransactionLoader; }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const cacheKeyFn = (obj: any) => stringify(obj); +export const cacheKeyFn = (obj: unknown) => stringify(obj) ?? '';