Skip to content

Commit

Permalink
Improve documentation for @semaphore/cli package (#771)
Browse files Browse the repository at this point in the history
docs(cli): improve code comments and readme of the @semaphore/cli package
  • Loading branch information
0xjei authored May 7, 2024
1 parent b9fa75c commit 6b6bc6a
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 11 deletions.
22 changes: 18 additions & 4 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,25 @@
</h4>
</div>

| Setting up a project, although not particularly complex, can be a lengthy process for some people. The Semaphore CLI reduces the set-up time from a few minutes to a few seconds. In addition, it can also be used to obtain on-chain group data. |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Semaphore CLI simplifies the process of setting up Semaphore projects and retrieving on-chain group data, reducing setup time from minutes to seconds. |
| ------------------------------------------------------------------------------------------------------------------------------------------------------ |

## 🛠 Install

Install the `@semaphore-protocol/cli` package globally:
To install Semaphore CLI globally:

```bash
npm i -g @semaphore-protocol/cli
```

or run specific commands with `npx`:
Alternatively, you can use `npx` to run commands without installing the package globally:

```bash
npx @semaphore-protocol/cli create my-app
```

This command sets up a new project in the `my-app` directory using the `monorepo-ethers` template.

## 📜 Usage

```
Expand All @@ -82,3 +84,15 @@ Commands:
get-proofs [options] [group-id] Get the proofs of a group from a supported network (e.g. sepolia or arbitrum).
help [command] Display help for a specific command.
```

## 🌐 Supported Networks

Semaphore CLI supports multiple Ethereum networks. Use the `get-groups` command to interact with groups on networks like Sepolia or Arbitrum.

## 📦 Supported Templates

When creating a new project, you can choose from several templates designed to integrate seamlessly with Semaphore's privacy protocols:

- **monorepo-ethers**: Hardhat + Next.js + SemaphoreEthers
- **monorepo-subgraph**: Hardhat + Next.js + SemaphoreSubgraph
- **contracts-hardhat**: Hardhat only, focused on smart contract development.
8 changes: 4 additions & 4 deletions packages/cli/src/checkLatestVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { lt as semverLt } from "semver"
const cliRegistryURL = "https://registry.npmjs.org/-/package/@semaphore-protocol/cli/dist-tags"

/**
* Checks the registry directly via the API, if that fails, tries the slower `npm view [package] version` command.
* This is important for users in environments where direct access to npm is blocked by a firewall, and packages are
* provided exclusively via a private registry.
* @param currentVersion The current version of the CLI.
* Checks for the latest version of the CLI tool against the registry. It first attempts to fetch the version directly
* via an API call. If this fails, possibly due to network restrictions, it falls back to using the `npm view` command.
* This method ensures that users behind a firewall or using a private registry can still check for updates.
* @param currentVersion The current version of the CLI being used.
*/
export default async function checkLatestVersion(currentVersion: string) {
let latestVersion: string
Expand Down
10 changes: 7 additions & 3 deletions packages/cli/src/getGroupIds.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { SemaphoreSubgraph, SemaphoreEthers } from "@semaphore-protocol/data"
import { SupportedNetwork } from "@semaphore-protocol/utils"
import logSymbols from "log-symbols"
import Spinner from "./spinner.js"

/**
* Gets all group ids on the specified network
* @param network The specified network
* Retrieves all group IDs from the Semaphore protocol on a specified network. This function first attempts to
* fetch the group IDs using the SemaphoreSubgraph interface. If that fails, it tries the SemaphoreEthers interface
* as a fallback. This dual-method approach ensures higher reliability in fetching data across different network conditions.
* @param network The blockchain network from which to fetch the group IDs.
* @returns A promise that resolves to an array of group IDs or null if an error occurs.
*/
export default async function getGroupIds(network): Promise<string[]> {
export default async function getGroupIds(network: SupportedNetwork): Promise<string[]> {
let groupIds: string[]

const spinner = new Spinner("Fetching groups")
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import getGroupIds from "./getGroupIds.js"
import { getGroupId, getProjectName, getSupportedNetwork, getSupportedTemplate } from "./inquirerPrompts.js"
import Spinner from "./spinner.js"

// Define the path to the package.json file to extract metadata for the CLI.
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
const { description, version } = JSON.parse(readFileSync(`${packagePath}/package.json`, "utf8"))

// List of supported templates for project creation.
const supportedTemplates = [
{
value: "monorepo-ethers",
Expand All @@ -32,6 +34,7 @@ const supportedTemplates = [
}
]

// Setup the CLI program with basic information and help text.
program
.name("semaphore")
.description(description)
Expand All @@ -46,6 +49,7 @@ program
}
})

// Define the 'create' command to scaffold new Semaphore projects.
program
.command("create")
.description("Create a Semaphore project with a supported template.")
Expand Down Expand Up @@ -78,15 +82,19 @@ program

await checkLatestVersion(version)

// Extract the template package into the project directory.
await pacote.extract(
`@semaphore-protocol/cli-template-${template}@${version}`,
`${currentDirectory}/${projectDirectory}`
)

// Decompress the template files after extraction.
await decompress(`${currentDirectory}/${projectDirectory}/files.tgz`, `${currentDirectory}/${projectDirectory}`)

// Clean up the compressed file after extraction.
unlinkSync(`${currentDirectory}/${projectDirectory}/files.tgz`)

// Copy the example environment file to the actual environment file.
copyFileSync(
`${currentDirectory}/${projectDirectory}/.env.example`,
`${currentDirectory}/${projectDirectory}/.env`
Expand All @@ -99,6 +107,7 @@ program
console.info(` ${chalk.cyan("cd")} ${projectDirectory}`)
console.info(` ${chalk.cyan("yarn install")}\n`)

// Read the package.json to list available npm scripts.
const { scripts } = JSON.parse(readFileSync(`${currentDirectory}/${projectDirectory}/package.json`, "utf8"))

if (scripts) {
Expand Down
20 changes: 20 additions & 0 deletions packages/cli/src/inquirerPrompts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import inquirer from "inquirer"

/**
* Prompts the user to input the name of their project. Provides a default name of "my-app".
* @returns A promise that resolves to the user's input for the project name.
*/
export async function getProjectName() {
const { projectName } = await inquirer.prompt({
name: "projectName",
Expand All @@ -10,6 +14,12 @@ export async function getProjectName() {
return projectName
}

/**
* Prompts the user to select a template from a list of supported templates. Each template is presented
* with its value and name for better clarity.
* @param supportedTemplates An array of objects, each containing a 'value' and 'name' property for the template.
* @returns A promise that resolves to the selected template's value.
*/
export async function getSupportedTemplate(supportedTemplates: { value: string; name: string }[]) {
const { selectedTemplate } = await inquirer.prompt({
name: "selectedTemplate",
Expand All @@ -24,6 +34,11 @@ export async function getSupportedTemplate(supportedTemplates: { value: string;
return selectedTemplate
}

/**
* Prompts the user to select a network from a list of supported networks.
* @param supportedNetworks An array of strings representing the supported networks.
* @returns A promise that resolves to the selected network.
*/
export async function getSupportedNetwork(supportedNetworks: string[]) {
const { selectedNetwork } = await inquirer.prompt({
name: "selectedNetwork",
Expand All @@ -35,6 +50,11 @@ export async function getSupportedNetwork(supportedNetworks: string[]) {
return selectedNetwork
}

/**
* Prompts the user to select a group ID from a list of existing group IDs.
* @param groupIds An array of strings representing the group IDs.
* @returns A promise that resolves to the selected group ID.
*/
export async function getGroupId(groupIds: string[]) {
const { selectedGroupId } = await inquirer.prompt({
name: "selectedGroupId",
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/spinner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import ora, { Ora } from "ora"

/**
* A utility class for managing a CLI spinner. This class encapsulates the functionality of the `ora` spinner,
* providing methods to start and stop the spinner. It is used to give visual feedback to the user during operations
* that have a noticeable delay, such as network requests.
*/
export default class Spinner {
private ora: Ora

Expand Down

0 comments on commit 6b6bc6a

Please sign in to comment.