171 lines
4.5 KiB
TypeScript
171 lines
4.5 KiB
TypeScript
import { EnumVar, StructVar, Var } from "@polkadot-api/metadata-builders"
|
|
import { NOTIN } from "@polkadot-api/react-builder"
|
|
import { Enum } from "polkadot-api"
|
|
import { mapObject } from "polkadot-api/utils"
|
|
|
|
const complexTypes = new Set<Var["type"]>([
|
|
"tuple",
|
|
"array",
|
|
"sequence",
|
|
"struct",
|
|
"enum",
|
|
"result",
|
|
"option",
|
|
])
|
|
export const isComplex = (type: Var["type"]) => complexTypes.has(type)
|
|
|
|
export const isEnumComplex = <T extends EnumVar>(
|
|
shape: T,
|
|
type: keyof T["value"],
|
|
): boolean => {
|
|
const innerShape = shape.value[type]
|
|
return isComplex(
|
|
innerShape.type === "lookupEntry" ? innerShape.value.type : innerShape.type,
|
|
)
|
|
}
|
|
|
|
export const getEnumInnerVar = <T extends EnumVar>(
|
|
shape: T,
|
|
type: keyof T["value"],
|
|
): Var => {
|
|
const innerShape = shape.value[type]
|
|
return innerShape.type === "lookupEntry" ? innerShape.value : innerShape
|
|
}
|
|
export const getEnumInnerType = <T extends EnumVar>(
|
|
shape: T,
|
|
type: keyof T["value"],
|
|
) => getEnumInnerVar(shape, type).type
|
|
|
|
export const getStructInnerType = <T extends StructVar>(
|
|
shape: T,
|
|
key: keyof T["value"],
|
|
) => {
|
|
return shape.value[key].type
|
|
}
|
|
|
|
const MAX_DEPTH = 5
|
|
export const getDefaultValue = (innerVar: Var, depth = 0): any => {
|
|
if (depth > MAX_DEPTH) return NOTIN
|
|
const nextDefault = (v: Var) => getDefaultValue(v, depth + 1)
|
|
|
|
switch (innerVar.type) {
|
|
case "void":
|
|
return null
|
|
case "option":
|
|
return undefined
|
|
case "sequence":
|
|
return []
|
|
case "struct":
|
|
return mapObject(innerVar.value, (v) => nextDefault(v))
|
|
case "array":
|
|
return new Array(innerVar.len)
|
|
.fill(0)
|
|
.map(() => nextDefault(innerVar.value))
|
|
case "tuple":
|
|
return innerVar.value.map(nextDefault)
|
|
case "enum": {
|
|
const selected = Object.entries(innerVar.value)[0]
|
|
return selected
|
|
? Enum(
|
|
selected[0],
|
|
nextDefault(
|
|
selected[1].type === "lookupEntry"
|
|
? selected[1].value
|
|
: selected[1],
|
|
),
|
|
)
|
|
: NOTIN
|
|
}
|
|
}
|
|
return NOTIN
|
|
}
|
|
|
|
export const getEnumDefaultValue = <T extends EnumVar>(
|
|
shape: T,
|
|
type: keyof T["value"],
|
|
) => {
|
|
const innerVar = getEnumInnerVar(shape, type)
|
|
return getDefaultValue(innerVar)
|
|
}
|
|
|
|
export const getFinalType = (shape: any, name: string) => {
|
|
const innerType = shape.value[name]
|
|
switch (innerType.type) {
|
|
case "primitive":
|
|
return innerType.value
|
|
case "compact":
|
|
return innerType.size
|
|
case "AccountId20":
|
|
case "AccountId32":
|
|
return innerType.type
|
|
}
|
|
}
|
|
|
|
type TypeComplexity = "inline" | "multiple" | "tree"
|
|
export const getTypeComplexity = (
|
|
lookupType: Var,
|
|
viewMode = false,
|
|
): TypeComplexity => {
|
|
switch (lookupType.type) {
|
|
case "array":
|
|
case "sequence":
|
|
if (
|
|
lookupType.value.type === "primitive" &&
|
|
lookupType.value.value === "u8"
|
|
) {
|
|
return "inline"
|
|
}
|
|
return maxComplexity(
|
|
"multiple",
|
|
getTypeComplexity(lookupType.value, viewMode),
|
|
)
|
|
case "tuple":
|
|
return reduceMaxComplexity(
|
|
"multiple",
|
|
lookupType.value.map((v) => () => getTypeComplexity(v, viewMode)),
|
|
)
|
|
case "enum":
|
|
return reduceMaxComplexity(
|
|
"inline",
|
|
Object.values(lookupType.value).map((v) => () => {
|
|
const inner = getTypeComplexity(
|
|
v.type === "lookupEntry" ? v.value : v,
|
|
viewMode,
|
|
)
|
|
return inner === "inline" ? "inline" : "tree"
|
|
}),
|
|
)
|
|
case "struct":
|
|
return reduceMaxComplexity(
|
|
"multiple",
|
|
Object.values(lookupType.value).map((v) => () => {
|
|
const inner = getTypeComplexity(v, viewMode)
|
|
return inner === "inline" ? "inline" : "tree"
|
|
}),
|
|
)
|
|
case "option":
|
|
return maxComplexity(
|
|
viewMode ? "inline" : "multiple",
|
|
getTypeComplexity(lookupType.value, viewMode),
|
|
)
|
|
case "result":
|
|
return reduceMaxComplexity(viewMode ? "inline" : "multiple", [
|
|
() => getTypeComplexity(lookupType.value.ok, viewMode),
|
|
() => getTypeComplexity(lookupType.value.ko, viewMode),
|
|
])
|
|
default:
|
|
return "inline"
|
|
}
|
|
}
|
|
const highCx: Array<TypeComplexity> = ["tree", "multiple"]
|
|
const maxComplexity = (a: TypeComplexity, b: TypeComplexity) =>
|
|
highCx.find((c) => a === c || b == c) ?? "inline"
|
|
const reduceMaxComplexity = (
|
|
initial: TypeComplexity,
|
|
fns: Array<() => TypeComplexity>,
|
|
) =>
|
|
fns.reduce((acc, fn) => {
|
|
if (acc === "tree") return acc
|
|
return maxComplexity(acc, fn())
|
|
}, initial)
|