• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cartesi / rollups-explorer / 10030569058

21 Jul 2024 06:42PM UTC coverage: 93.314% (-1.0%) from 94.266%
10030569058

push

github

web-flow
#178 Create responsive table component (#206)

818 of 956 branches covered (85.56%)

Branch coverage included in aggregate %.

175 of 312 new or added lines in 2 files covered. (56.09%)

2 existing lines in 1 file now uncovered.

9022 of 9589 relevant lines covered (94.09%)

52.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.0
/packages/ui/src/ERC1155DepositForm/useGetTokenMetadata.tsx
1
import { cond, isNil, isNotNil } from "ramda";
1✔
2
import { useEffect, useState } from "react";
1✔
3

1✔
4
export type UseGetTokenMetadata = (
1✔
5
    uri?: string,
1✔
6
    tokenId?: bigint,
1✔
7
) => TokenMetadataResult;
1✔
8

1✔
9
interface PrepareUrlResult {
1✔
10
    validURL: boolean;
1✔
11
    isHttp: boolean;
1✔
12
    error?: TypeError;
1✔
13
    result?: URL;
1✔
14
    url: string;
1✔
15
}
1✔
16

1✔
17
type TokenMetadata = Record<string, any>;
1✔
18

1✔
19
interface FetchResult {
1✔
20
    data?: TokenMetadata;
1✔
21
    error?: Error;
1✔
22
}
1✔
23

1✔
24
export type State =
1✔
25
    | "idle"
1✔
26
    | "fetching"
1✔
27
    | "success"
1✔
28
    | "errored"
1✔
29
    | "not_http"
1✔
30
    | "http_network_error";
1✔
31

1✔
32
export interface TokenMetadataResult {
1✔
33
    state: State;
1✔
34
    /** Tells if the URI returned is defined using the http protocol. */
1✔
35
    isHttp?: boolean;
1✔
36
    /** Parsed URL based on EIP-1155 standard @link{https://eips.ethereum.org/EIPS/eip-1155#metadata} */
1✔
37
    url?: string;
1✔
38
    /** A wide type to support the returned JSON based on EIP-1155 @link{https://eips.ethereum.org/EIPS/eip-1155#erc-1155-metadata-uri-json-schema}*/
1✔
39
    data?: TokenMetadata;
1✔
40
    /** Any error returned during fetch phase.*/
1✔
41
    error?: Error;
1✔
42
}
1✔
43

1✔
44
interface MetaCache {
1✔
45
    [key: string]: TokenMetadataResult;
1✔
46
}
1✔
47

1✔
48
const prepareUrl = (uri: string, id: bigint): PrepareUrlResult => {
1✔
49
    const regex = /\{id\}/;
×
50
    try {
×
51
        const url = uri.replace(regex, id.toString());
×
52
        const result = new URL(url);
×
53
        return {
×
54
            validURL: true,
×
55
            isHttp: result.protocol.includes("http"),
×
56
            result,
×
57
            url,
×
58
        };
×
59
    } catch (error: any) {
×
60
        return {
×
61
            validURL: false,
×
62
            isHttp: false,
×
63
            error: error as TypeError,
×
64
            url: uri,
×
65
        };
×
66
    }
×
67
};
×
68

1✔
69
const fetchMetadata = async (
1✔
70
    result: PrepareUrlResult,
×
71
    signal: AbortSignal,
×
72
): Promise<FetchResult> => {
×
73
    if (!result.validURL || !result.isHttp) return {};
×
74

×
75
    return fetch(result.url, { signal })
×
76
        .then(async (r) => {
×
77
            if (r.ok) {
×
78
                return r.json().then((data: Record<string, any>) => ({ data }));
×
79
            }
×
80
            const errorMessage = await r
×
81
                .text()
×
82
                .catch(() => `Status: ${r.status}`);
×
83
            return { error: new Error(errorMessage) };
×
84
        })
×
85
        .catch((e: Error) => ({ error: e }));
×
86
};
×
87

1✔
88
type DeriveStateProps = {
1✔
89
    urlResult: PrepareUrlResult;
1✔
90
    fetchResult: FetchResult;
1✔
91
};
1✔
92

1✔
93
const deriveState = cond<DeriveStateProps[], State>([
1✔
94
    [
1✔
95
        ({ urlResult, fetchResult }) =>
1✔
96
            urlResult.isHttp && isNil(fetchResult.error),
×
97
        () => "success",
1✔
98
    ],
1✔
99
    [
1✔
100
        ({ urlResult }) => urlResult.validURL && !urlResult.isHttp,
1✔
101
        () => "not_http",
1✔
102
    ],
1✔
103
    [
1✔
104
        ({ urlResult, fetchResult }) =>
1✔
105
            urlResult.isHttp && isNotNil(fetchResult.error),
×
106
        () => "http_network_error",
1✔
107
    ],
1✔
108
    [
1✔
109
        ({ fetchResult, urlResult }) =>
1✔
110
            isNotNil(fetchResult.error) || isNotNil(urlResult.error),
×
111
        () => "errored",
1✔
112
    ],
1✔
113
    [() => true, () => "idle"],
1✔
114
]);
1✔
115

1✔
116
export const useGetTokenMetadata: UseGetTokenMetadata = (uri, id) => {
1✔
117
    const [cache, setCache] = useState<MetaCache>({});
×
118
    const [result, setResult] = useState<TokenMetadataResult>({
×
119
        state: "idle",
×
120
    });
×
121

×
122
    useEffect(() => {
×
123
        if (isNil(uri) || isNil(id)) {
×
124
            setResult(() => ({ state: "idle" }));
×
125
            return;
×
126
        }
×
127

×
128
        const update = async (uri: string, id: bigint, signal: AbortSignal) => {
×
129
            const urlResult = prepareUrl(uri, id);
×
130
            const fetchResult = await fetchMetadata(urlResult, signal);
×
131

×
132
            if (isNil(fetchResult.error)) {
×
133
                setCache((cache) => {
×
134
                    cache[uri + id] = result;
×
135
                    return cache;
×
136
                });
×
137
            }
×
138

×
139
            if (fetchResult.error?.name === "AbortError") {
×
140
                console.log(`Request to ${urlResult.url} aborted.`);
×
141
                return;
×
142
            }
×
143

×
144
            const result = {
×
145
                state: deriveState({ fetchResult, urlResult }),
×
146
                error: fetchResult.error,
×
147
                data: fetchResult.data,
×
148
                isHttp: urlResult.isHttp,
×
149
                url: urlResult.url,
×
150
            };
×
151

×
152
            setResult(result);
×
153
        };
×
154

×
155
        if (uri !== undefined && id !== undefined) {
×
156
            const abortController = new AbortController();
×
157
            const cached = cache[uri + id];
×
158
            if (cached !== undefined) {
×
159
                setResult(cached);
×
160
            } else {
×
161
                setResult(() => ({ state: "fetching" }));
×
162
                update(uri, id, abortController.signal);
×
163
            }
×
164

×
165
            return () => {
×
166
                console.log(`calling abort on ${id}`);
×
167
                abortController.abort(
×
168
                    `Token id ${id} metadata request aborted.`,
×
169
                );
×
170
            };
×
171
        }
×
172
    }, [uri, id, cache]);
×
173

×
174
    return result;
×
175
};
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc