diff --git a/packages/crypto-frontmatter/cli.js b/packages/crypto-frontmatter/cli.js new file mode 100755 index 000000000..ae51adc77 --- /dev/null +++ b/packages/crypto-frontmatter/cli.js @@ -0,0 +1,3 @@ +#! /usr/bin/env node +/* eslint-disable */ +require('./dist/cli.js'); diff --git a/packages/crypto-frontmatter/package.json b/packages/crypto-frontmatter/package.json index fdcc557ea..07f4aace7 100644 --- a/packages/crypto-frontmatter/package.json +++ b/packages/crypto-frontmatter/package.json @@ -19,6 +19,9 @@ ] } }, + "bin": { + "crypto-frontmatter": "./cli.js" + }, "files": [ "dist" ], @@ -40,23 +43,26 @@ "jest": { "preset": "@workspace/jest-preset" }, + "dependencies": { + "clipanion": "3.2.1" + }, "devDependencies": { "@crypto-frontmatter/eip155-1-erc20": "workspace:*", "@workspace/jest-preset": "workspace:*", "@workspace/tsconfig": "workspace:*" }, "peerDependencies": { - "@crypto-frontmatter/eip155-1-erc20": "*", - "@crypto-frontmatter/eip155-10-erc20": "*", - "@crypto-frontmatter/eip155-1313161554-erc20": "*", - "@crypto-frontmatter/eip155-137-erc20": "*", - "@crypto-frontmatter/eip155-42161-erc20": "*", - "@crypto-frontmatter/eip155-42220-erc20": "*", - "@crypto-frontmatter/eip155-43114-erc20": "*", - "@crypto-frontmatter/eip155-56-erc20": "*", - "@crypto-frontmatter/eip155-8453-erc20": "*", - "@crypto-frontmatter/tip474-728126428-trc10": "*", - "@crypto-frontmatter/tip474-728126428-trc20": "*" + "@crypto-frontmatter/eip155-1-erc20": "workspace:*", + "@crypto-frontmatter/eip155-10-erc20": "workspace:*", + "@crypto-frontmatter/eip155-1313161554-erc20": "workspace:*", + "@crypto-frontmatter/eip155-137-erc20": "workspace:*", + "@crypto-frontmatter/eip155-42161-erc20": "workspace:*", + "@crypto-frontmatter/eip155-42220-erc20": "workspace:*", + "@crypto-frontmatter/eip155-43114-erc20": "workspace:*", + "@crypto-frontmatter/eip155-56-erc20": "workspace:*", + "@crypto-frontmatter/eip155-8453-erc20": "workspace:*", + "@crypto-frontmatter/tip474-728126428-trc10": "workspace:*", + "@crypto-frontmatter/tip474-728126428-trc20": "workspace:*" }, "peerDependenciesMeta": { "@crypto-frontmatter/eip155-1-erc20": { diff --git a/packages/crypto-frontmatter/src/cli.ts b/packages/crypto-frontmatter/src/cli.ts new file mode 100644 index 000000000..4250b830b --- /dev/null +++ b/packages/crypto-frontmatter/src/cli.ts @@ -0,0 +1,34 @@ +import { copyFile, mkdir } from 'node:fs/promises'; +import { join } from 'node:path'; + +import { Command, Option, runExit } from 'clipanion'; + +import { getFrontmatterIndexArray, getInstalledFrontmatterCollection, getNodeModulesPath } from './index'; + +export class MirrorCommand extends Command { + static override paths = [[`mirror`]]; + private target = Option.String(); + + async execute(): Promise { + await mkdir(this.target, { recursive: true }); + + const collections = await getInstalledFrontmatterCollection(); + for (const collection of collections) { + let count = 0; + const indexArray = await getFrontmatterIndexArray(collection.caip2, collection.namespace); + for (const frontmatterIndex of indexArray) { + for (const frontmatterImage of frontmatterIndex.fields.images) { + const from = getNodeModulesPath(collection.caip2, collection.namespace, frontmatterImage.path); + const to = join(this.target, frontmatterImage.path); + count++; + await copyFile(from, to); + } + } + + this.context.stdout.write(`Mirrored ${count} files for "${collection.caip2}/${collection.namespace}"\n`); + } + } +} + +// noinspection JSIgnoredPromiseFromCall +void runExit([MirrorCommand]); diff --git a/packages/crypto-frontmatter/src/index.ts b/packages/crypto-frontmatter/src/index.ts index 127e5ca5f..0d41c961f 100644 --- a/packages/crypto-frontmatter/src/index.ts +++ b/packages/crypto-frontmatter/src/index.ts @@ -1,5 +1,5 @@ import { createHash } from 'node:crypto'; -import { readFile } from 'node:fs/promises'; +import { readdir, readFile, stat } from 'node:fs/promises'; import { join } from 'node:path'; export interface FrontmatterLink { @@ -39,19 +39,10 @@ export interface FrontmatterContent extends FrontmatterIndex { html: string; } -export const SupportedCollections = [ - ['eip155:1', 'erc20'], - ['eip155:10', 'erc20'], - ['eip155:56', 'erc20'], - ['eip155:137', 'erc20'], - ['eip155:8453', 'erc20'], - ['eip155:42161', 'erc20'], - ['eip155:42220', 'erc20'], - ['eip155:43114', 'erc20'], - ['eip155:1313161554', 'erc20'], - ['tip474:728126428', 'trc10'], - ['tip474:728126428', 'trc20'], -]; +export interface FrontmatterCollection { + caip2: string; + namespace: string; +} /** * Decode CAIP-19 into CAIP-2, Asset NAMESPACE, and Asset REFERENCE @@ -68,6 +59,13 @@ function sha256(input: string): string { return createHash('sha256').update(input).digest('hex'); } +function hasFile(filepath: string): Promise { + return stat(filepath).then( + () => true, + () => false, + ); +} + /** * Encode CAIP-19 into fileId * If Namespace is ERC20, the address field will be converted to lowercase. @@ -82,9 +80,9 @@ export function computeFileId(caip19: string): string { return sha256(caip19); } -export async function readCryptoFrontmatterFile(caip2: string, namespace: string, file: string): Promise { +export function getNodeModulesPath(caip2: string, namespace: string, file: string) { const [caip2Type, caip2Reference] = caip2.split(':'); - const path = join( + return join( 'node_modules', '@crypto-frontmatter', `${caip2Type}-${caip2Reference}-${namespace}`, @@ -92,20 +90,37 @@ export async function readCryptoFrontmatterFile(caip2: string, namespace: string 'Frontmatter', file, ); - const contents = await readFile(path, { - encoding: 'utf-8', - }); - return JSON.parse(contents); +} + +export async function getInstalledFrontmatterCollection(): Promise { + const scopePath = join('node_modules', '@crypto-frontmatter'); + const collections: FrontmatterCollection[] = []; + + for (const dir of await readdir(scopePath)) { + const packagePath = join(scopePath, dir, 'package.json'); + if (!(await hasFile(packagePath))) { + continue; + } + const contents = await readFile(packagePath, { + encoding: 'utf-8', + }); + collections.push(JSON.parse(contents).config); + } + return collections; } /** - * Get FrontmatterIndex collection of CAIP-2 and Asset TYPE + * Get the collection FrontmatterIndex with CAIP-2 and Asset TYPE * @param caip2 {string} * @param namespace {string} * @return {FrontmatterIndex[]} */ -export async function getFrontmatterCollection(caip2: string, namespace: string): Promise { - return readCryptoFrontmatterFile(caip2, namespace, 'index.json'); +export async function getFrontmatterIndexArray(caip2: string, namespace: string): Promise { + const path = getNodeModulesPath(caip2, namespace, 'index.json'); + const contents = await readFile(path, { + encoding: 'utf-8', + }); + return JSON.parse(contents); } /** @@ -120,5 +135,13 @@ export async function getFrontmatterContent(caip19: string): Promise { - const collection = await getFrontmatterCollection('eip155:1', 'erc20'); + const collection = await getFrontmatterIndexArray('eip155:1', 'erc20'); expect(collection).toStrictEqual( expect.arrayContaining([ expect.objectContaining({ @@ -42,10 +42,32 @@ it('should getFrontmatterContent of eip155:1/erc20:0x00000000008943c65cAf789FFFC width: 512, height: 512, }, - path: expect.stringMatching(/[0-f]{64}\.logo\.png/), + path: expect.stringMatching(/[0-9a-f]{64}\.png/), }, ], }, html: '

Dharma USD Coin

', }); }); + +it('should getFrontmatterContent of eip155:1/erc20:0', async () => { + const frontmatterContent = await getFrontmatterContent('eip155:1/erc20:0'); + expect(frontmatterContent).toBeUndefined(); +}); + +it('should getInstalledFrontmatterCollection', async () => { + const collections = await getInstalledFrontmatterCollection(); + expect(collections).toStrictEqual([ + { caip2: 'eip155:1', namespace: 'erc20' }, + { caip2: 'eip155:10', namespace: 'erc20' }, + { caip2: 'eip155:1313161554', namespace: 'erc20' }, + { caip2: 'eip155:137', namespace: 'erc20' }, + { caip2: 'eip155:42161', namespace: 'erc20' }, + { caip2: 'eip155:42220', namespace: 'erc20' }, + { caip2: 'eip155:43114', namespace: 'erc20' }, + { caip2: 'eip155:56', namespace: 'erc20' }, + { caip2: 'eip155:8453', namespace: 'erc20' }, + { caip2: 'tip474:728126428', namespace: 'trc10' }, + { caip2: 'tip474:728126428', namespace: 'trc20' }, + ]); +}); diff --git a/packages/eip155-1-erc20/package.json b/packages/eip155-1-erc20/package.json index 32757f5ef..dc37f2836 100644 --- a/packages/eip155-1-erc20/package.json +++ b/packages/eip155-1-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:1", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-10-erc20/package.json b/packages/eip155-10-erc20/package.json index 8c70181f4..dc4509c10 100644 --- a/packages/eip155-10-erc20/package.json +++ b/packages/eip155-10-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:10", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-1313161554-erc20/package.json b/packages/eip155-1313161554-erc20/package.json index db52129b7..2484c833b 100644 --- a/packages/eip155-1313161554-erc20/package.json +++ b/packages/eip155-1313161554-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:1313161554", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-137-erc20/package.json b/packages/eip155-137-erc20/package.json index 23191dc4b..95b999838 100644 --- a/packages/eip155-137-erc20/package.json +++ b/packages/eip155-137-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:137", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-42161-erc20/package.json b/packages/eip155-42161-erc20/package.json index b064052e6..8b568c761 100644 --- a/packages/eip155-42161-erc20/package.json +++ b/packages/eip155-42161-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:42161", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-42220-erc20/package.json b/packages/eip155-42220-erc20/package.json index 0c5d1feb7..d641a916d 100644 --- a/packages/eip155-42220-erc20/package.json +++ b/packages/eip155-42220-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:42220", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-43114-erc20/package.json b/packages/eip155-43114-erc20/package.json index bcf7d442e..4c9d96be8 100644 --- a/packages/eip155-43114-erc20/package.json +++ b/packages/eip155-43114-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:43114", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-56-erc20/package.json b/packages/eip155-56-erc20/package.json index fe2136607..f11ab49e4 100644 --- a/packages/eip155-56-erc20/package.json +++ b/packages/eip155-56-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:56", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/eip155-8453-erc20/package.json b/packages/eip155-8453-erc20/package.json index 6391f657d..5ddbb83e9 100644 --- a/packages/eip155-8453-erc20/package.json +++ b/packages/eip155-8453-erc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "eip155:8453", + "namespace": "erc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/tip474-728126428-trc10/package.json b/packages/tip474-728126428-trc10/package.json index bd0857df7..d69eb4bb1 100644 --- a/packages/tip474-728126428-trc10/package.json +++ b/packages/tip474-728126428-trc10/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "tip474:728126428", + "namespace": "trc10" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/packages/tip474-728126428-trc20/package.json b/packages/tip474-728126428-trc20/package.json index 5e8f1789e..a00b36854 100644 --- a/packages/tip474-728126428-trc20/package.json +++ b/packages/tip474-728126428-trc20/package.json @@ -14,6 +14,10 @@ "build": "contented build", "clean": "rm -rf dist" }, + "config": { + "caip2": "tip474:728126428", + "namespace": "trc20" + }, "devDependencies": { "@contentedjs/contented": "^7.1.0", "@workspace/contented-config": "workspace:*" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d03e1c379..10ec618ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,35 +51,38 @@ importers: packages/crypto-frontmatter: dependencies: '@crypto-frontmatter/eip155-10-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-10-erc20 '@crypto-frontmatter/eip155-1313161554-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-1313161554-erc20 '@crypto-frontmatter/eip155-137-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-137-erc20 '@crypto-frontmatter/eip155-42161-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-42161-erc20 '@crypto-frontmatter/eip155-42220-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-42220-erc20 '@crypto-frontmatter/eip155-43114-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-43114-erc20 '@crypto-frontmatter/eip155-56-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-56-erc20 '@crypto-frontmatter/eip155-8453-erc20': - specifier: '*' - version: 0.1.2 + specifier: workspace:* + version: link:../eip155-8453-erc20 '@crypto-frontmatter/tip474-728126428-trc10': - specifier: '*' + specifier: workspace:* version: link:../tip474-728126428-trc10 '@crypto-frontmatter/tip474-728126428-trc20': - specifier: '*' + specifier: workspace:* version: link:../tip474-728126428-trc20 + clipanion: + specifier: 3.2.1 + version: 3.2.1(typanion@3.14.0) devDependencies: '@crypto-frontmatter/eip155-1-erc20': specifier: workspace:* @@ -752,38 +755,6 @@ packages: - supports-color - typanion - /@crypto-frontmatter/eip155-10-erc20@0.1.2: - resolution: {integrity: sha512-yplo/Z0YsWoEmFeaxzjs30mRKjWrrcGuGpRos8tfTB1AryqrHgEMGundBIRbl0PDHz4ulISbu+3th95hi79Xyw==} - dev: false - - /@crypto-frontmatter/eip155-1313161554-erc20@0.1.2: - resolution: {integrity: sha512-I+wnlrYYLO5SeM09VcYtNFthZxjb4jUEidOoADdfg7goKrgvUWKaa3dtIqZIbbzIg/g2OzqCMCUNXT4k02G6aQ==} - dev: false - - /@crypto-frontmatter/eip155-137-erc20@0.1.2: - resolution: {integrity: sha512-4+yeteZcPpVrCSqadDpyfD23LKD68ULqajOfceFi3EID4VSgHbfXyTE+GBTeODulh6X/yzcfYbbhl3g5Dbs/HA==} - dev: false - - /@crypto-frontmatter/eip155-42161-erc20@0.1.2: - resolution: {integrity: sha512-h9LFSQEh9JjXTKuDz46ftKmCwZ44TOI4XXin/SvQPscTclZYW97iWVKc1EHJoj7Ymi+czoSxRRvd5DtdQGlmMw==} - dev: false - - /@crypto-frontmatter/eip155-42220-erc20@0.1.2: - resolution: {integrity: sha512-MH0vnAFoGr0BDA3jvEVB0euyibX88C9petHN2e6QiIA04zD3HpWfVCWirrsb5iuh8OhQtMpI0szqD09yrVwAUw==} - dev: false - - /@crypto-frontmatter/eip155-43114-erc20@0.1.2: - resolution: {integrity: sha512-pJH84fhhjkMx17/3EdTYhAGRmS/QtEiIEPzE25umxTjV+9ijNbg7DHoVZKrKX+qVj81lMEskWEn6ePvsjEKNSQ==} - dev: false - - /@crypto-frontmatter/eip155-56-erc20@0.1.2: - resolution: {integrity: sha512-XVKDreWHEUPKl7qezoE1tY9sF5U0r3tC0BHAnEg11UX1Ec4pJqaPuujK/dr5Pn5XqKMQrVZNdvpDOizQwaqj7g==} - dev: false - - /@crypto-frontmatter/eip155-8453-erc20@0.1.2: - resolution: {integrity: sha512-2nJscd/xcVHlk+2wy9HpXU1bXhSya9uClSaPW/MHZPszaJnb8Ip1buweFFoJy9q1Rn4gPryWVBzNFquwAergNA==} - dev: false - /@emotion/is-prop-valid@0.8.8: resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} requiresBuild: true diff --git a/website/.gitignore b/website/.gitignore index 693988f4c..5131e77e2 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -1,6 +1,7 @@ # next.js /.next/ /out/ +/public/crypto-frontmatter/ # misc .DS_Store diff --git a/website/app/[caip2]/[asset]/page.tsx b/website/app/[caip2]/[asset]/page.tsx index a9d02b9ba..dba311cd8 100644 --- a/website/app/[caip2]/[asset]/page.tsx +++ b/website/app/[caip2]/[asset]/page.tsx @@ -1,8 +1,8 @@ import { FrontmatterIndex, - getFrontmatterCollection, getFrontmatterContent, - SupportedCollections, + getFrontmatterIndexArray, + getInstalledFrontmatterCollection, } from 'crypto-frontmatter'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; @@ -18,10 +18,10 @@ function asCaip19(caip2: string, asset: string): string { export async function generateStaticParams(): Promise[0]['params'][]> { const params: Parameters[0]['params'][] = []; - for (const [caip2, type] of SupportedCollections) { - const collection = await getFrontmatterCollection(caip2, type); - for (const frontmatter of collection) { - const [caip2, asset] = frontmatter.path.split('/'); + const collections = await getInstalledFrontmatterCollection(); + for (const { caip2, namespace } of collections) { + for (const index of await getFrontmatterIndexArray(caip2, namespace)) { + const [caip2, asset] = index.path.split('/'); params.push({ caip2, asset }); } } diff --git a/website/components/contented/FrontmatterImage.tsx b/website/components/contented/FrontmatterImage.tsx index eec96d9d5..c3a131212 100644 --- a/website/components/contented/FrontmatterImage.tsx +++ b/website/components/contented/FrontmatterImage.tsx @@ -1,6 +1,5 @@ 'use client'; import type { FrontmatterIndex } from 'crypto-frontmatter'; -import { requireCryptoFrontmatter } from 'crypto-frontmatter/require'; import Image from 'next/image'; import type { ReactElement } from 'react'; @@ -12,7 +11,7 @@ export function FrontmatterImage(props: { frontmatter: FrontmatterIndex; type: ' return (