Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ This Turborepo includes the following example applications:
| `@shelby-protocol/ai-image-generation` | Shelby AI image generation example | [`apps/ai-image-generation`](./apps/ai-image-generation) |
| `@shelby-protocol/cross-chain-accounts` | Shelby cross chain accounts example | [`apps/cross-chain-accounts`](./apps/cross-chain-accounts) |
| `@shelby-protocol/download-example` | An example app to demonstrate downloading blobs using the Shelby SDK | [`apps/download-blob`](./apps/download-blob) |
| `@shelby-examples/ethereum-file-upload` | Simple Ethereum file upload to Shelby using wagmi and RainbowKit | [`apps/ethereum/file-upload`](./apps/ethereum/file-upload) |
| `@shelby-protocol/list-example` | An example app to demonstrate listing blobs using the Shelby SDK | [`apps/list-blob`](./apps/list-blob) |
| `solana-file-upload` | Simple Solana file upload to Shelby using @solana/react-hooks | [`apps/solana/file-upload`](./apps/solana/file-upload) |
| `token-gated` | Next.js, Tailwind, @solana/react-hooks, Anchor vault program | [`apps/solana/token-gated`](./apps/solana/token-gated) |
| `@shelby-protocol/upload-example` | An example app to demonstrate uploading blobs using the Shelby SDK | [`apps/upload-blob`](./apps/upload-blob) |

<!-- APPS_TABLE_END -->
Expand Down
1 change: 1 addition & 0 deletions apps/ethereum/file-upload/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "@shelby-examples/ethereum-file-upload",
"description": "Simple Ethereum file upload to Shelby using wagmi and RainbowKit",
"private": true,
"version": "0.0.0",
"scripts": {
Expand Down
76 changes: 49 additions & 27 deletions packages/table-generator/src/scanner.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { readdirSync, readFileSync, statSync } from "node:fs";
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";
import type { MonorepoApps, MonorepoItem, PackageInfo } from "./types.js";

const IGNORED_DIRS = new Set(["node_modules"]);

/**
* Get package.json content for a given path
*/
Expand All @@ -23,6 +25,11 @@ function getPackageInfo(packagePath: string): PackageInfo | null {

/**
* Scan a directory for packages/apps
*
* Workspaces may be nested one or more levels deep (for example
* `apps/solana/file-upload`, declared in pnpm-workspace.yaml as
* `apps/solana/*`), so directories without a package.json of their own are
* treated as grouping directories and recursed into.
*/
function scanDirectory(
dirPath: string,
Expand All @@ -32,37 +39,52 @@ function scanDirectory(
const items: MonorepoItem[] = [];

try {
const dirs = readdirSync(dirPath);
// Sorted so the generated table is stable across filesystems
const dirs = readdirSync(dirPath).sort();
for (const dir of dirs) {
if (dir.startsWith(".") || IGNORED_DIRS.has(dir)) {
continue;
}

const fullPath = join(dirPath, dir);
if (statSync(fullPath).isDirectory()) {
const pkgInfo = getPackageInfo(fullPath);
if (pkgInfo) {
let repository: string | undefined;
if (typeof pkgInfo.repository === "string") {
repository = pkgInfo.repository;
} else if (
typeof pkgInfo.repository === "object" &&
pkgInfo.repository?.url
) {
repository = pkgInfo.repository.url;
}
if (!statSync(fullPath).isDirectory()) {
continue;
}

if (repository) {
// Clean up git URLs
repository = repository.replace(/^git\+/, "").replace(/\.git$/, "");
}
const itemPath = `${relativePath}/${dir}`;

items.push({
name: pkgInfo.name,
description: pkgInfo.description || "No description provided",
path: `${relativePath}/${dir}`,
type,
private: pkgInfo.private || false,
homepage: pkgInfo.homepage,
repository,
});
// Grouping directory: no package.json of its own, so look inside it
if (!existsSync(join(fullPath, "package.json"))) {
items.push(...scanDirectory(fullPath, type, itemPath));
continue;
}

const pkgInfo = getPackageInfo(fullPath);
if (pkgInfo) {
let repository: string | undefined;
if (typeof pkgInfo.repository === "string") {
repository = pkgInfo.repository;
} else if (
typeof pkgInfo.repository === "object" &&
pkgInfo.repository?.url
) {
repository = pkgInfo.repository.url;
}

if (repository) {
// Clean up git URLs
repository = repository.replace(/^git\+/, "").replace(/\.git$/, "");
}

items.push({
name: pkgInfo.name,
description: pkgInfo.description || "No description provided",
path: itemPath,
type,
private: pkgInfo.private || false,
homepage: pkgInfo.homepage,
repository,
});
}
}
} catch (error) {
Expand Down