Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
node_modules
bin
bin
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ bin
.yarn-error.log
package-lock.json
*.csv
.idea
.idea
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Follow the steps below to run the CLI locally:

2. Install all dependencies by running `yarn`

3. Run `yarn local:link`. It should create a symlink pointing to `./bin/src/index.js`.
3. Run `yarn local:link`. It should create a symlink pointing to `./bin/index.js`.

4. Run `yarn start` to transpile the typescript into javascript.

Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The command-line interface for versum.
- [Contributing](#contributing)
- [How to use](#how-to-use)
- [Export](#export)
- [Templates](#templates)

## Usage

Expand Down Expand Up @@ -36,7 +37,7 @@ versum
versum -h
```

### Export
## Export

The versum CLI allows you to export several chunks of data into `.csv` files.

Expand All @@ -54,3 +55,13 @@ versum export wallet-collectors
versum export wallet-collectors --wallet tz1eht4WAjkqU7kaupJd8qCDmec9HuKfGf68
versum export wallet-collectors --wallet tz1eht4WAjkqU7kaupJd8qCDmec9HuKfGf68 --platform versum
```

## Templates

You can quickly generate new working folders from existing [templates](https://github.com/versumstudios/templates). This way you can start new projects without having to worry about boilerplate code.

```bash
versum template
versum template --template versum-web
versum template --template fxhash-gt
```
18 changes: 13 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@
"type": "git",
"url": "https://github.com/versumstudios/cli.git"
},
"keywords": [
"versum",
"cli",
"tezos"
],
"scripts": {
"start": "rm -rf ./bin && concurrently --raw \"tsc -w -p .\" \"tsc-alias -w\"",
"build": "rm -rf ./bin && tsc && tsc-alias",
"dev": "rimraf ./bin && ncc build ./src/index.ts -w -o bin/",
"build": "rimraf ./bin && ncc build ./src/index.ts -o ./bin/ --minify --no-cache --no-source-map-register",
"test": "echo \"Error: no test specified\" && exit 1",
"local:install": "npm install -g .",
"local:uninstall": "npm uninstall -g @versumstudios/cli",
Expand All @@ -23,7 +28,7 @@
"bin"
],
"bin": {
"versum": "./bin/src/index.js"
"versum": "./bin/index.js"
},
"engines": {
"node": ">=16"
Expand All @@ -40,10 +45,12 @@
"@types/node": "^18.0.6",
"@types/node-fetch": "^2.6.2",
"@types/objects-to-csv": "^1.3.1",
"@types/rimraf": "^3.0.2",
"@types/tar": "^6.1.1",
"@types/update-notifier": "^6.0.1",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"concurrently": "^7.3.0",
"@vercel/ncc": "^0.34.0",
"eslint": "^8.20.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.3.0",
Expand All @@ -53,17 +60,18 @@
"husky": "^8.0.1",
"prettier": "^2.7.1",
"ts-node": "^10.9.1",
"tsc-alias": "^1.7.0",
"typescript": "^4.7.4"
},
"dependencies": {
"@taquito/utils": "^13.0.1",
"chalk": "4.1.2",
"commander": "^9.4.0",
"got": "^12.3.0",
"inquirer": "8.0.0",
"node-fetch": "2.6.2",
"objects-to-csv": "^1.3.6",
"ora": "5.4.1",
"tar": "^6.1.11",
"update-notifier": "5.1.0"
}
}
9 changes: 5 additions & 4 deletions src/actions/export-token-collectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import inquirer, { Answers, Separator } from 'inquirer';
import fetch from 'node-fetch';
import ora from 'ora';

import { CONTRACT_VERSUM, ERRORS, getContractFromPlatform, MESSAGES, PLATFORMS, TEZTOK_API } from '@constants';
import { CollectorsType } from '@custom-types/collectors';
import { validateContractAddress } from '@taquito/utils';
import { SaveToFile } from '@utils/csv';
import { error, info } from '@utils/logger';

import { CONTRACT_VERSUM, ERRORS, getContractFromPlatform, MESSAGES, PLATFORMS, TEZTOK_API } from '../constants';
import { CollectorsType } from '../types';
import { SaveToFile } from '../utils/csv';
import { error, info } from '../utils/logger';

const handleAction = (address: string, token: string) => {
const query = `
Expand Down
9 changes: 5 additions & 4 deletions src/actions/export-wallet-collectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import inquirer, { Separator } from 'inquirer';
import fetch from 'node-fetch';
import ora from 'ora';

import { ERRORS, getKeyFromPlatform, MESSAGES, PLATFORMS, TEZTOK_API } from '@constants';
import { CollectorsType } from '@custom-types/collectors';
import { validateAddress } from '@taquito/utils';
import { SaveToFile } from '@utils/csv';
import { error, info } from '@utils/logger';

import { ERRORS, getKeyFromPlatform, MESSAGES, PLATFORMS, TEZTOK_API } from '../constants';
import { CollectorsType } from '../types';
import { SaveToFile } from '../utils/csv';
import { error, info } from '../utils/logger';

const handleAction = (address: string, platform?: PLATFORMS) => {
const query = `
Expand Down
118 changes: 118 additions & 0 deletions src/actions/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import fs from 'fs';
import inquirer from 'inquirer';
import fetch from 'node-fetch';
import ora from 'ora';

// import path from 'path';
import { ERRORS, MESSAGES } from '../constants';
import { GithubProps } from '../types';
import { copyDirectoy, deleteDirectory, makeDirectory, parseFiles } from '../utils/filesystem';
import { downloadAndExtractRepo } from '../utils/github';
import { error, info } from '../utils/logger';

const DEFAULT_NAME = 'my-app';
const DEFAULT_DESCRIPTION = '@versumstudios/cli template';

const GITHUB_USER = 'versumstudios';
const GITHUB_REPO = 'templates';
const GITHUB_BRANCH = 'main';

const handleAction = async (
template: string,
name: string = DEFAULT_NAME,
description: string = DEFAULT_DESCRIPTION
) => {
const now = Date.now();

const appName = name.replace(/\s+/g, '-').toLowerCase();
const appDescription = description.toLowerCase();

const rootDir = process.cwd();
const tempDir = `${rootDir}/temp`;
const templateDir = `${tempDir}/${template}`;
const targetDir = `${rootDir}/${appName}`;

if (fs.existsSync(targetDir)) {
throw new Error('Directory already exists');
}

await makeDirectory(tempDir);

await downloadAndExtractRepo(tempDir, {
username: GITHUB_USER,
name: GITHUB_REPO,
branch: GITHUB_BRANCH,
});

await copyDirectoy(templateDir, targetDir);

await deleteDirectory(tempDir);

await parseFiles(targetDir, appName, appDescription);

return `"${template}" template created in ${Date.now() - now}ms`;
};

export const action = async (options: Record<string, string>) => {
// if options are present, bypass the user promp
if (options.template) {
handleAction(options.template)
.then((message) => info(message))
.catch((e) => {
error(e?.toString() || ERRORS.ERROR_GENERATE_TEMPLATE);
});
return;
}

// gets a list of all templates
const result = await fetch(`https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/git/trees/${GITHUB_BRANCH}`);
const { tree } = await result.json();

if (!tree) {
throw new Error(ERRORS.ERROR_EXPORT_COLLECTOR);
}

// filter list to only return folders
const choices = tree.filter((e: GithubProps) => e.type === 'tree').map((e: GithubProps) => e.path);

// pass the templates into inquirer
const questions = [
{
type: 'input',
name: 'name',
message: MESSAGES.ENTER_PROJECT_NAME,
default() {
return DEFAULT_NAME;
},
},
{
type: 'input',
name: 'description',
message: MESSAGES.ENTER_PROJECT_DESCRIPTION,
default() {
return DEFAULT_DESCRIPTION;
},
},
{
type: 'list',
name: 'template',
message: MESSAGES.SELECT_TEMPLATE,
choices,
},
];

inquirer.prompt(questions).then(({ template, name, description }: Record<string, string>) => {
// select contract address from platform alias
const spinner = ora(MESSAGES.GENERATE_TEMPLATE).start();

handleAction(template, name, description)
.then((message: string) => {
spinner.succeed();
info(message);
})
.catch((e) => {
spinner.fail();
error(e?.toString() || ERRORS.ERROR_GENERATE_TEMPLATE);
});
});
};
2 changes: 1 addition & 1 deletion src/actions/test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from '@utils/logger';
import { log } from '../utils/logger';

export const action = () => {
log('test action');
Expand Down
10 changes: 5 additions & 5 deletions src/commands/export.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Command } from 'commander';

import { action as exportTokenCollectorsAction } from '@actions/export-token-collectors';
import { action as exportCollectorsAction } from '@actions/export-wallet-collectors';

export const command = new Command('export').description('export token data to csv');
import { action as exportTokenCollectorsAction } from '../actions/export-token-collectors';
import { action as exportCollectorsAction } from '../actions/export-wallet-collectors';

const command = new Command('export').description('export token data to csv');
command
.command('token-collectors')
.description('exports token collectors')
.option('-c, --contract <value>', 'contract address')
.option('-t, --token <value>', 'token id')
.action(exportTokenCollectorsAction);

command
.command('wallet-collectors')
.description('exports wallet collectors')
.option('-w, --wallet <value>', 'user wallet address')
.option('-p, --platform <value>', 'platform')
.action(exportCollectorsAction);

export default command;
11 changes: 11 additions & 0 deletions src/commands/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Command } from 'commander';

import { action as templateAction } from '../actions/template';

const command = new Command()
.command('template')
.description('creates a new project from a template')
.option('-t, --template <value>', 'specify a template')
.action(templateAction);

export default command;
5 changes: 3 additions & 2 deletions src/commands/test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command } from 'commander';

import { action as testAction } from '@actions/test';
import { action as testAction } from '../actions/test';

export const command = new Command().command('test').description('test description').action(testAction);
const command = new Command().command('test').description('test description').action(testAction);
export default command;
21 changes: 10 additions & 11 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import chalk from 'chalk';
// import fs from 'fs';
import * as pkg from 'package.json';

import pkg from '../package.json';

export const LOGO = `

██╗ ██╗███████╗██████╗ ███████╗██╗ ██╗███╗ ███╗
██║ ██║██╔════╝██╔══██╗██╔════╝██║ ██║████╗ ████║
██║ ██║█████╗ ██████╔╝███████╗██║ ██║██╔████╔██║
╚██╗ ██╔╝██╔══╝ ██╔══██╗╚════██║██║ ██║██║╚██╔╝██║
╚████╔╝ ███████╗██║ ██║███████║╚██████╔╝██║ ╚═╝ ██║
╚═══╝ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝`;

export const COMMANDS = `${__dirname}/commands`;

export const ACTIONS = './actions';

export const PACKAGE = pkg; // JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, 'utf-8'));
export const PACKAGE = pkg;

export const VERSION = `${PACKAGE.name} ${PACKAGE.version}`;
export const VERSION = `v:${PACKAGE.version}`;

export const DESCRIPTION = `
${LOGO}
${chalk.bgBlack(chalk.green(VERSION))}`;
${LOGO} ${chalk.bgBlack(chalk.green(VERSION))}\n`;

export const TEZTOK_API = 'https://api.teztok.com/v1/graphql';

Expand Down Expand Up @@ -83,13 +77,18 @@ export const getKeyFromPlatform = (platform: PLATFORMS) => {

export enum MESSAGES {
FETCHING_DATA = 'Fetching data',
GENERATE_TEMPLATE = 'Generate template',
SELECT_PLATFORM = 'Select platform',
SELECT_TEMPLATE = 'Select template',
ENTER_USER_ADDRESS = 'Enter wallet address',
ENTER_CONTRACT_ADDRESS = 'Enter contract address',
ENTER_TOKEN_ID = 'Enter Token ID',
ENTER_PROJECT_NAME = 'Enter project name',
ENTER_PROJECT_DESCRIPTION = 'Enter project description',
}

export enum ERRORS {
ERROR_INVALID_ADDRESS = 'Invalid address',
ERROR_EXPORT_COLLECTOR = 'Error exporting collectors',
ERROR_GENERATE_TEMPLATE = 'Error generate template',
}
Loading