From 47c8436fcf165650155a4fa7513ddb8264910bb1 Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Mon, 29 Apr 2024 12:45:42 +0200 Subject: [PATCH] feat: export only changed names --- src/{ => CommonTypes}/CommonType.tsx | 0 src/{ => CommonTypes}/CommonTypes.tsx | 23 +- src/CommonTypes/Export.tsx | 102 ++++++++ src/CommonTypes/commonTypes.state.ts | 165 +++++++++++++ src/CommonTypes/index.ts | 1 + src/{ => CommonTypes}/typeReferences.state.ts | 2 +- src/commonTypes.state.ts | 217 ------------------ 7 files changed, 271 insertions(+), 239 deletions(-) rename src/{ => CommonTypes}/CommonType.tsx (100%) rename src/{ => CommonTypes}/CommonTypes.tsx (82%) create mode 100644 src/CommonTypes/Export.tsx create mode 100644 src/CommonTypes/commonTypes.state.ts create mode 100644 src/CommonTypes/index.ts rename src/{ => CommonTypes}/typeReferences.state.ts (99%) delete mode 100644 src/commonTypes.state.ts diff --git a/src/CommonType.tsx b/src/CommonTypes/CommonType.tsx similarity index 100% rename from src/CommonType.tsx rename to src/CommonTypes/CommonType.tsx diff --git a/src/CommonTypes.tsx b/src/CommonTypes/CommonTypes.tsx similarity index 82% rename from src/CommonTypes.tsx rename to src/CommonTypes/CommonTypes.tsx index cb6d90e..085c85e 100644 --- a/src/CommonTypes.tsx +++ b/src/CommonTypes/CommonTypes.tsx @@ -6,12 +6,8 @@ import { Components, Virtuoso, VirtuosoHandle } from "react-virtuoso" import { firstValueFrom } from "rxjs" import { twMerge } from "tailwind-merge" import { CommonType } from "./CommonType" -import { - commonTypeNames$, - commonTypes$, - newKnownTypes$, - setSearch, -} from "./commonTypes.state" +import { ExportKnownTypes } from "./Export" +import { commonTypeNames$, commonTypes$, setSearch } from "./commonTypes.state" export function CommonTypes({ className }: { className?: string }) { const commonTypes = useStateObservable(commonTypes$) @@ -86,18 +82,3 @@ const Item: Components["Item"] = forwardRef( /> ), ) - -const ExportKnownTypes = () => { - const newKnownTypes = useStateObservable(newKnownTypes$) - - return ( -
-

Here are the known types object for the selected chains

-
-        
-          {JSON.stringify(newKnownTypes, null, 2)}
-        
-      
-
- ) -} diff --git a/src/CommonTypes/Export.tsx b/src/CommonTypes/Export.tsx new file mode 100644 index 0000000..4f37d1c --- /dev/null +++ b/src/CommonTypes/Export.tsx @@ -0,0 +1,102 @@ +import { state, useStateObservable } from "@react-rxjs/core" +import { combineKeys, createSignal } from "@react-rxjs/utils" +import { combineLatest, map, scan } from "rxjs" +import { selectedChains$ } from "../ChainPicker" +import { + chainTypes$, + commonTypeNames$, + getCurrentKnownType, +} from "./commonTypes.state" +import { Checkbox } from "@radix-ui/themes" + +type RepositoryEntry = { + name: string + chains: string + paths: string[] + type: string +} +const allNewKnownTypes$ = state( + combineLatest({ + chains: combineKeys(selectedChains$, chainTypes$), + names: commonTypeNames$, + }).pipe( + map(({ chains, names }) => { + const result: Record = {} + + Object.entries(names).forEach(([checksum, name]) => { + if (!name) return + + const chainsWithType = Array.from(chains.keys()).filter( + (chain) => checksum in chains.get(chain)!, + ) + if (chainsWithType.length === 0) return + + const paths = Array.from( + new Set( + chainsWithType.flatMap((chain) => + chains + .get(chain)! + [checksum].map((type) => type.entry.path.join(".")), + ), + ), + ) + + const selectedChain = chains.get(chainsWithType[0])! + const chainType = selectedChain[checksum][0] + const type = `Enum(${Object.keys(chainType.value).join(", ")})` + + result[checksum] = { + name, + chains: chainsWithType.join(", "), + paths, + type, + } + }) + + return result + }), + ), + {}, +) + +const [toggleOnlyChanges$, toggleOnlyChanges] = createSignal() +const onlyChanges$ = state( + toggleOnlyChanges$.pipe(scan((acc) => !acc, true)), + true, +) + +const newKnownTypes$ = state( + combineLatest([allNewKnownTypes$, onlyChanges$]).pipe( + map(([allNewKnownTypes, onlyChanges]) => + onlyChanges + ? Object.fromEntries( + Object.entries(allNewKnownTypes).filter( + ([checksum, entry]) => + entry.name !== getCurrentKnownType(checksum), + ), + ) + : allNewKnownTypes, + ), + ), + {}, +) + +export const ExportKnownTypes = () => { + const onlyChanges = useStateObservable(onlyChanges$) + const newKnownTypes = useStateObservable(newKnownTypes$) + + return ( +
+

Here are the known types object for the selected chains

+ +
+        
+          {JSON.stringify(newKnownTypes, null, 2)}
+        
+      
+
+ ) +} diff --git a/src/CommonTypes/commonTypes.state.ts b/src/CommonTypes/commonTypes.state.ts new file mode 100644 index 0000000..5a3dced --- /dev/null +++ b/src/CommonTypes/commonTypes.state.ts @@ -0,0 +1,165 @@ +import { knownTypesRepository } from "@polkadot-api/codegen" +import { + LookupEntry, + getChecksumBuilder, + getLookupFn, +} from "@polkadot-api/metadata-builders" +import { V14, V15 } from "@polkadot-api/substrate-bindings" +import { state, withDefault } from "@react-rxjs/core" +import { combineKeys, createSignal, mergeWithKey } from "@react-rxjs/utils" +import { + EMPTY, + catchError, + combineLatest, + distinctUntilChanged, + map, + scan, +} from "rxjs" +import { selectedChains$ } from "../ChainPicker" +import { metadatas } from "../api/metadatas" + +export type MetadataEntry = + (V15 | V14)["lookup"] extends Array ? R : never +export type EnumEntry = LookupEntry & { type: "enum"; entry: MetadataEntry } +export const chainTypes$ = state( + (chain: string) => + metadatas[chain].pipe( + catchError(() => EMPTY), + map((metadata) => { + const lookup = getLookupFn(metadata.lookup) + const checksumBuilder = getChecksumBuilder(metadata) + + const result: Record = {} + for (let i = 0; i < metadata.lookup.length; i++) { + if (metadata.lookup[i].def.tag !== "variant") continue + + const def = lookup(i) + if (def.type !== "enum") continue + + const checksum = checksumBuilder.buildDefinition(i) + if (!checksum) { + throw new Error("unreachable") + } + + result[checksum] = result[checksum] ?? [] + result[checksum].push({ ...def, entry: metadata.lookup[i] }) + } + + return result + }), + ), + {}, +) + +export const commonTypes$ = state( + combineKeys(selectedChains$, chainTypes$).pipe( + map((chains) => { + const result: Record< + string, + Array<{ + chain: string + type: EnumEntry + }> + > = {} + + for (let entry of chains.entries()) { + const [chain, types] = entry + for (let checksum of Object.keys(types)) { + result[checksum] = [ + ...(result[checksum] ?? []), + ...types[checksum].map((type) => ({ chain, type })), + ] + } + } + + return Object.entries(result) + .map(([checksum, types]) => ({ + checksum, + types, + })) + .sort((a, b) => b.types.length - a.types.length) + }), + ), + [], +) + +export const getCurrentKnownType = (checksum: string) => { + const entry = knownTypesRepository[checksum] + if (!entry) return null + return typeof entry === "string" ? entry : entry.name +} + +export const [searchChange$, setSearch] = createSignal() +export const search$ = state(searchChange$, "") + +export const [nameChange$, setTypeName] = createSignal<{ + checksum: string + name: string +}>() +export const commonTypeNames$ = state( + mergeWithKey({ + types: combineKeys(selectedChains$, chainTypes$), + name: nameChange$, + }).pipe( + scan((acc: Record, value) => { + const result = { ...acc } + if (value.type === "types") { + for (const chain of value.payload.changes) { + if (!value.payload.has(chain)) continue + const checksums = Object.keys(value.payload.get(chain)!) + checksums.forEach((checksum) => { + result[checksum] = result[checksum] ?? getCurrentKnownType(checksum) + }) + } + } else { + result[value.payload.checksum] = value.payload.name + } + + return result + }, {}), + ), + {}, +) + +export const currentName$ = state( + (checksum: string) => + commonTypeNames$.pipe( + map((v) => v[checksum] ?? ""), + distinctUntilChanged(), + ), + "", +) +export const isHighlighted$ = state( + (checksum: string) => + combineLatest([currentName$(checksum), search$]).pipe( + map( + ([name, search]) => + search.length && + (checksum.includes(search) || + name.toLocaleLowerCase().includes(search)), + ), + ), + false, +) + +const duplicateNames$ = commonTypeNames$.pipeState( + map((names) => { + const inverted: Record = {} + Object.entries(names).forEach(([checksum, name]) => { + inverted[name] = inverted[name] ?? [] + inverted[name].push(checksum) + }) + return Object.fromEntries( + Object.entries(inverted).filter(([, checksums]) => checksums.length > 1), + ) + }), + withDefault({} as Record), +) +export const nameDuplicate$ = state( + (name: string) => + duplicateNames$.pipe( + map((duplicates) => duplicates[name] ?? []), + distinctUntilChanged((a, b) => a.join(",") === b.join(",")), + ), + [], +) diff --git a/src/CommonTypes/index.ts b/src/CommonTypes/index.ts new file mode 100644 index 0000000..b1a20be --- /dev/null +++ b/src/CommonTypes/index.ts @@ -0,0 +1 @@ +export * from "./CommonTypes" diff --git a/src/typeReferences.state.ts b/src/CommonTypes/typeReferences.state.ts similarity index 99% rename from src/typeReferences.state.ts rename to src/CommonTypes/typeReferences.state.ts index 96dc274..d96d348 100644 --- a/src/typeReferences.state.ts +++ b/src/CommonTypes/typeReferences.state.ts @@ -6,7 +6,7 @@ import { } from "@polkadot-api/metadata-builders" import { state } from "@react-rxjs/core" import { map } from "rxjs" -import { metadatas } from "./api/metadatas" +import { metadatas } from "../api/metadatas" type References = { direct: string[]; indirect: string[] } const emptyReferences: References = { direct: [], indirect: [] } diff --git a/src/commonTypes.state.ts b/src/commonTypes.state.ts deleted file mode 100644 index 8ca9e6f..0000000 --- a/src/commonTypes.state.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { knownTypesRepository } from "@polkadot-api/codegen"; -import { - LookupEntry, - getChecksumBuilder, - getLookupFn, -} from "@polkadot-api/metadata-builders"; -import { V14, V15 } from "@polkadot-api/substrate-bindings"; -import { state, withDefault } from "@react-rxjs/core"; -import { combineKeys, createSignal, mergeWithKey } from "@react-rxjs/utils"; -import { - EMPTY, - catchError, - combineLatest, - distinctUntilChanged, - map, - scan, -} from "rxjs"; -import { selectedChains$ } from "./ChainPicker"; -import { metadatas } from "./api/metadatas"; - -export type MetadataEntry = (V15 | V14)["lookup"] extends Array - ? R - : never; -export type EnumEntry = LookupEntry & { type: "enum"; entry: MetadataEntry }; -const chainTypes$ = state( - (chain: string) => - metadatas[chain].pipe( - catchError(() => EMPTY), - map((metadata) => { - const lookup = getLookupFn(metadata.lookup); - const checksumBuilder = getChecksumBuilder(metadata); - - const result: Record = {}; - for (let i = 0; i < metadata.lookup.length; i++) { - if (metadata.lookup[i].def.tag !== "variant") continue; - - const def = lookup(i); - if (def.type !== "enum") continue; - - const checksum = checksumBuilder.buildDefinition(i); - if (!checksum) { - throw new Error("unreachable"); - } - - result[checksum] = result[checksum] ?? []; - result[checksum].push({ ...def, entry: metadata.lookup[i] }); - } - - return result; - }) - ), - {} -); - -export const commonTypes$ = state( - combineKeys(selectedChains$, chainTypes$).pipe( - map((chains) => { - const result: Record< - string, - Array<{ - chain: string; - type: EnumEntry; - }> - > = {}; - - for (let entry of chains.entries()) { - const [chain, types] = entry; - for (let checksum of Object.keys(types)) { - result[checksum] = [ - ...(result[checksum] ?? []), - ...types[checksum].map((type) => ({ chain, type })), - ]; - } - } - - return Object.entries(result) - .map(([checksum, types]) => ({ - checksum, - types, - })) - .sort((a, b) => b.types.length - a.types.length); - }) - ), - [] -); - -export const getCurrentKnownType = (checksum: string) => { - const entry = knownTypesRepository[checksum]; - if (!entry) return null; - return typeof entry === "string" ? entry : entry.name; -}; - -export const [searchChange$, setSearch] = createSignal(); -export const search$ = state(searchChange$, ""); - -export const [nameChange$, setTypeName] = createSignal<{ - checksum: string; - name: string; -}>(); -export const commonTypeNames$ = state( - mergeWithKey({ - types: combineKeys(selectedChains$, chainTypes$), - name: nameChange$, - }).pipe( - scan((acc: Record, value) => { - const result = { ...acc }; - if (value.type === "types") { - for (const chain of value.payload.changes) { - if (!value.payload.has(chain)) continue; - const checksums = Object.keys(value.payload.get(chain)!); - checksums.forEach((checksum) => { - result[checksum] = - result[checksum] ?? getCurrentKnownType(checksum); - }); - } - } else { - result[value.payload.checksum] = value.payload.name; - } - - return result; - }, {}) - ), - {} -); - -export const currentName$ = state( - (checksum: string) => - commonTypeNames$.pipe( - map((v) => v[checksum] ?? ""), - distinctUntilChanged() - ), - "" -); -export const isHighlighted$ = state( - (checksum: string) => - combineLatest([currentName$(checksum), search$]).pipe( - map( - ([name, search]) => - search.length && - (checksum.includes(search) || - name.toLocaleLowerCase().includes(search)) - ) - ), - false -); - -type RepositoryEntry = { - name: string; - chains: string; - paths: string[]; - type: string; -}; -export const newKnownTypes$ = state( - combineLatest({ - chains: combineKeys(selectedChains$, chainTypes$), - names: commonTypeNames$, - }).pipe( - map(({ chains, names }) => { - const result: Record = {}; - - Object.entries(names).forEach(([checksum, name]) => { - if (!name) return; - - const chainsWithType = Array.from(chains.keys()).filter( - (chain) => checksum in chains.get(chain)! - ); - if (chainsWithType.length === 0) return; - - const paths = Array.from( - new Set( - chainsWithType.flatMap((chain) => - chains - .get(chain)! - [checksum].map((type) => type.entry.path.join(".")) - ) - ) - ); - - const selectedChain = chains.get(chainsWithType[0])!; - const chainType = selectedChain[checksum][0]; - const type = `Enum(${Object.keys(chainType.value).join(", ")})`; - - result[checksum] = { - name, - chains: chainsWithType.join(", "), - paths, - type, - }; - }); - - return result; - }) - ), - {} -); - -const duplicateNames$ = commonTypeNames$.pipeState( - map((names) => { - const inverted: Record = {}; - Object.entries(names).forEach(([checksum, name]) => { - inverted[name] = inverted[name] ?? []; - inverted[name].push(checksum); - }); - return Object.fromEntries( - Object.entries(inverted).filter(([, checksums]) => checksums.length > 1) - ); - }), - withDefault({} as Record) -); -export const nameDuplicate$ = state( - (name: string) => - duplicateNames$.pipe( - map((duplicates) => duplicates[name] ?? []), - distinctUntilChanged((a, b) => a.join(",") === b.join(",")) - ), - [] -);