Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
feat(cli): Update generator to use templates (#2085)
Browse files Browse the repository at this point in the history
  • Loading branch information
immasandwich committed Jan 10, 2023
1 parent 5608e5d commit f9de204
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 179 deletions.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -18,7 +18,9 @@
</div>

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors-)

<!-- ALL-CONTRIBUTORS-BADGE:END -->

## Description
Expand Down Expand Up @@ -71,7 +73,6 @@ pnpm studio create-group [app-id]
```bash
pnpm studio create-token-fetcher [app-id]
pnpm studio create-contract-position-fetcher [app-id]
pnpm studio create-balance-fetcher [app-id]
```

## Clearing the cache
Expand Down
15 changes: 7 additions & 8 deletions cli/commands/create-app.ts
@@ -1,10 +1,9 @@
import { Command } from '@oclif/core';
import fse from 'fs-extra';
import { ensureDir } from 'fs-extra';
import { zipObject } from 'lodash';

import { AppAction } from '../../src/app/app.interface';
import { generateAppDefinition } from '../generators/generate-app-definition';
import { generateAppIndex } from '../generators/generate-app-index';
import { generateAppModule } from '../generators/generate-app-module';
import {
promptAppDescription,
Expand Down Expand Up @@ -32,22 +31,22 @@ export default class CreateApp extends Command {
const networks = await promptAppNetworks();
const tags = await promptAppTags();

fse.ensureDir(`./src/apps/${appId}`);
fse.ensureDir(`./src/apps/${appId}/assets`);
fse.ensureDir(`./src/apps/${appId}/contracts`);
fse.ensureDir(`./src/apps/${appId}/contracts/abis`);
await ensureDir(`./src/apps/${appId}`);
await ensureDir(`./src/apps/${appId}/assets`);
await ensureDir(`./src/apps/${appId}/contracts`);
await ensureDir(`./src/apps/${appId}/contracts/abis`);
for (const network of networks) {
fse.ensureDir(`./src/apps/${appId}/${network}`);
await ensureDir(`./src/apps/${appId}/${network}`);
}

await generateAppModule(appId);
await generateAppIndex(appId);
await generateAppDefinition({
id: appId,
name: appName,
description: appDescription,
url: appUrl,
tags,
links: {},
supportedNetworks: zipObject(
networks,
networks.map(() => [AppAction.VIEW]),
Expand Down
28 changes: 0 additions & 28 deletions cli/commands/create-balance-fetcher.ts

This file was deleted.

13 changes: 3 additions & 10 deletions cli/commands/create-contract-position-fetcher.ts
Expand Up @@ -7,13 +7,7 @@ import { addGroupToAppDefinition } from '../generators/generate-app-definition';
import { addContractPositionFetcherToAppModule } from '../generators/generate-app-module';
import { generateContractPositionFetcher } from '../generators/generate-contract-position-fetcher';
import { loadAppDefinition } from '../generators/utils';
import {
promptAppGroupId,
promptAppNetwork,
promptNewGroupId,
promptNewGroupLabel,
promptNewGroupType,
} from '../prompts';
import { promptAppGroupId, promptAppNetwork, promptNewGroupId, promptNewGroupLabel } from '../prompts';

export default class CreateContractPositionFetcher extends Command {
static description = 'Creates a contract position fetcher in a given app';
Expand All @@ -26,15 +20,14 @@ export default class CreateContractPositionFetcher extends Command {
const appId = args.appId;

const definition = await loadAppDefinition(appId);
const groupIds = Object.values(definition.groups).map(v => v.id);
const networks = Object.keys(definition.supportedNetworks);
const groupIds = Object.values(definition.groups ?? {}).map(v => v.id);
const networks = Object.keys(definition.supportedNetworks ?? {});

let groupId = await promptAppGroupId(groupIds);
let group: AppGroup | null = null;
if (!groupId) {
const newGroupId = await promptNewGroupId(groupIds);
const newGroupLabel = await promptNewGroupLabel();
const newGroupType = await promptNewGroupType();
group = { id: newGroupId, label: newGroupLabel, type: GroupType.POSITION };
groupId = newGroupId;
}
Expand Down
2 changes: 1 addition & 1 deletion cli/commands/create-group.ts
Expand Up @@ -17,7 +17,7 @@ export default class CreateGroup extends Command {
const appId = args.appId;

const definition = await loadAppDefinition(appId);
const groupIds = Object.values(definition.groups).map(v => v.id);
const groupIds = Object.values(definition.groups ?? {}).map(v => v.id);

const id = await promptNewGroupId(groupIds);
const label = await promptNewGroupLabel();
Expand Down
12 changes: 2 additions & 10 deletions cli/commands/create-token-fetcher.ts
Expand Up @@ -15,21 +15,13 @@ export default class CreateTokenFetcher extends Command {
static args = [{ name: 'appId', description: 'The application id ', required: true }];
static flags = {};

private async loadDefinition(appId: string) {
const modPath = `../src/apps/${appId}/${appId}.definition`;
const mod = require(modPath);
const key = Object.keys(mod).find(v => /_DEFINITION/.test(v));
if (!key) throw new Error(`No matched export found in ${modPath}`);
return mod[key];
}

async run(): Promise<void> {
const { args } = await this.parse(CreateTokenFetcher);
const appId = args.appId;

const definition = await loadAppDefinition(appId);
const groupIds = Object.values(definition.groups).map(v => v.id);
const networks = Object.keys(definition.supportedNetworks);
const groupIds = Object.values(definition.groups ?? {}).map(v => v.id);
const networks = Object.keys(definition.supportedNetworks ?? {});

let groupId = await promptAppGroupId(groupIds);
let group: AppGroup | null = null;
Expand Down
2 changes: 0 additions & 2 deletions cli/commands/index.ts
Expand Up @@ -2,7 +2,6 @@ import { Command } from '@oclif/core';

import ClearCache from './clear-cache';
import CreateApp from './create-app';
import CreateBalanceFetcher from './create-balance-fetcher';
import CreateContractPositionFetcher from './create-contract-position-fetcher';
import CreateGroup from './create-group';
import CreateTokenFetcher from './create-token-fetcher';
Expand All @@ -19,7 +18,6 @@ export const commands: Record<string, typeof Command> = {
'create-app': CreateApp,
'create-group': CreateGroup,
'create-token-fetcher': CreateTokenFetcher,
'create-balance-fetcher': CreateBalanceFetcher,
'create-contract-position-fetcher': CreateContractPositionFetcher,
'clear-cache': ClearCache,
'set-network-provider': SetNetworkProvider,
Expand Down
10 changes: 5 additions & 5 deletions cli/commands/set-network-provider.ts
Expand Up @@ -66,16 +66,16 @@ export default class SetNetworkProvider extends Command {
}
}

private deleteLineEnv(network: Network) {
private async deleteLineEnv(network: Network) {
const envVarKey = NetworkProviderService.getEnvVarKey(network);

// Create .env file if not exist
this.upsertFile(this.envFileName);
await this.upsertFile(this.envFileName);

// Delete the line related to the specified network if exists
const envFileLines = fs.readFileSync(this.envFileName).toString().trim().split('\n');
const envFileLine = envFileLines.findIndex(line => line.startsWith(`${envVarKey}=`));
if (envFileLine >= 0) envFileLines[envFileLine] = null;
if (envFileLine >= 0) envFileLines[envFileLine] = '';

// Rewrite file without the line
const newEnvFile = compact(envFileLines).join('\n');
Expand All @@ -96,11 +96,11 @@ export default class SetNetworkProvider extends Command {
const network = await this.promptNetwork();
const action = await this.promptAction();

this.deleteLineEnv(network);
await this.deleteLineEnv(network);

if (action === 'custom') {
const url = await this.promptNetworkProviderUrl();
this.setCustomProvider(network, url);
await this.setCustomProvider(network, url);
}
}
}
11 changes: 5 additions & 6 deletions cli/generators/generate-app-definition.ts
Expand Up @@ -11,7 +11,7 @@ import { formatAndWrite } from './utils';

import t = recast.types.namedTypes;

export async function generateAppDefinition(appDefinition: Partial<AppDefinitionObject>) {
export async function generateAppDefinition(appDefinition: AppDefinitionObject) {
const appDefinitionName = `${strings.upperCase(appDefinition.id)}_DEFINITION`;
const appClassName = strings.titleCase(appDefinition.id);

Expand Down Expand Up @@ -39,10 +39,9 @@ export async function generateAppDefinition(appDefinition: Partial<AppDefinition
links: ${JSON.stringify(appDefinition.links ?? {})},
supportedNetworks: {
${entries(appDefinition.supportedNetworks)
.map(([nk, n]) => `[Network.${networkToKey[nk]}]: [${n.map(v => `AppAction.${actionToKey[v]}`).join(',')}]`)
.map(([nk, n]) => `[Network.${networkToKey[nk]}]: [${n!.map(v => `AppAction.${actionToKey[v]}`).join(',')}]`)
.join(',')}
},
primaryColor: '${appDefinition.primaryColor ?? '#fff'}',
});
@Register.AppDefinition(${appDefinitionName}.id)
Expand Down Expand Up @@ -71,11 +70,11 @@ export const addGroupToAppDefinition = async ({ appId, group }: { appId: string;
const imports = value.body.filter((v): v is t.ImportDeclaration => v.type === 'ImportDeclaration');

const appInterfaceImport = imports.find(v => v.source.value === '~app/app.interface');
const appInterfaceImportedNames = appInterfaceImport.specifiers.map(v => v as t.ImportSpecifier);
const appInterfaceImportedNames = appInterfaceImport!.specifiers!.map(v => v as t.ImportSpecifier);
const hasGroupTypeImport = appInterfaceImportedNames.find(t => t.imported.name === 'GroupType');

if (!hasGroupTypeImport) {
appInterfaceImport.specifiers.push(b.importSpecifier(b.identifier('GroupType')));
appInterfaceImport!.specifiers!.push(b.importSpecifier(b.identifier('GroupType')));
}

this.traverse(path);
Expand All @@ -101,7 +100,7 @@ export const addGroupToAppDefinition = async ({ appId, group }: { appId: string;
]),
);

(groups.value as t.ObjectExpression).properties.push(newGroupProperty);
(groups!.value as t.ObjectExpression).properties.push(newGroupProperty);
}

this.traverse(path);
Expand Down
21 changes: 0 additions & 21 deletions cli/generators/generate-app-index.ts

This file was deleted.

40 changes: 0 additions & 40 deletions cli/generators/generate-balance-fetcher.ts

This file was deleted.

68 changes: 46 additions & 22 deletions cli/generators/generate-contract-position-fetcher.ts
Expand Up @@ -6,40 +6,64 @@ import { strings } from '../strings';
import { formatAndWrite } from './utils';

export async function generateContractPositionFetcher(appId: string, groupId: string, network: Network) {
const appDefinitionName = `${strings.upperCase(appId)}_DEFINITION`;
const appCamelCase = strings.camelCase(appId);
const appTitleCase = strings.titleCase(appCamelCase);
const groupKey = strings.camelCase(groupId);
const groupTitleCase = strings.titleCase(groupKey);

const networkKey = Object.keys(Network).filter(k => network.includes(Network[k]));
const networkTitleCase = strings.titleCase(network);

const content = dedent`
import { Inject } from '@nestjs/common';
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface';
import { Register } from '~app-toolkit/decorators';
import { PositionFetcher } from '~position/position-fetcher.interface';
import { ContractPosition } from '~position/position.interface';
import { Network } from '~types/network.interface';
import { BigNumberish, Contract } from 'ethers';
import { ${appTitleCase}ContractFactory } from '../contracts';
import { ${appDefinitionName} } from '../${appId}.definition';
import { APP_TOOLKIT, IAppToolkit } from '~app-toolkit/app-toolkit.interface';
import { PositionTemplate } from '~app-toolkit/decorators/position-template.decorator';
import { DefaultDataProps } from '~position/display.interface';
import { ContractPositionTemplatePositionFetcher } from '~position/template/contract-position.template.position-fetcher';
import {
GetDefinitionsParams,
DefaultContractPositionDefinition,
GetTokenDefinitionsParams,
UnderlyingTokenDefinition,
GetDisplayPropsParams,
GetTokenBalancesParams,
} from '~position/template/contract-position.template.types';
const appId = ${appDefinitionName}.id;
const groupId = ${appDefinitionName}.groups.${groupKey}.id;
const network = Network.${networkKey};
import { ${appTitleCase}ContractFactory } from '../contracts';
@Register.ContractPositionFetcher({ appId, groupId, network })
export class ${networkTitleCase}${appTitleCase}${groupTitleCase}ContractPositionFetcher implements PositionFetcher<ContractPosition> {
@PositionTemplate()
export class ${networkTitleCase}${appTitleCase}${groupTitleCase}ContractPositionFetcher extends ContractPositionTemplatePositionFetcher<Contract> {
groupLabel: string;
constructor(
@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit,
@Inject(${appTitleCase}ContractFactory) private readonly ${appCamelCase}ContractFactory: ${appTitleCase}ContractFactory,
) {}
async getPositions() {
return [];
@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit,
@Inject(${appTitleCase}ContractFactory) protected readonly ${appCamelCase}ContractFactory: ${appTitleCase}ContractFactory,
) {
super(appToolkit);
}
getContract(_address: string): Contract {
throw new Error('Method not implemented.');
}
getDefinitions(_params: GetDefinitionsParams): Promise<DefaultContractPositionDefinition[]> {
throw new Error('Method not implemented.');
}
getTokenDefinitions(
_params: GetTokenDefinitionsParams<Contract, DefaultContractPositionDefinition>,
): Promise<UnderlyingTokenDefinition[] | null> {
throw new Error('Method not implemented.');
}
getLabel(
_params: GetDisplayPropsParams<Contract, DefaultDataProps, DefaultContractPositionDefinition>,
): Promise<string> {
throw new Error('Method not implemented.');
}
getTokenBalancesPerPosition(_params: GetTokenBalancesParams<Contract, DefaultDataProps>): Promise<BigNumberish[]> {
throw new Error('Method not implemented.');
}
}
`;
Expand Down

0 comments on commit f9de204

Please sign in to comment.