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(","))
- ),
- []
-);