Changes in codegen to remove lint warnings in generated watcher (#368)

* Codegen declare resultDataTypes before queries in gql schema

* Update codegen templates to remove lint warnings

* Add flag to overwrite existing watcher in target directory

* Codegen set up pre-commit lint

* Codegen generate .npmrc

* Codegen refactor  code for pre-commit lint

* Update codegen templates with eslint rule exceptions

* Fix missing comma in codegen template

* Set husky preCommit file permission to executable

---------

Co-authored-by: Dhruv Srivastava <dhruvdhs.ds@gmail.com>
This commit is contained in:
Nabarun Gogoi 2023-04-24 12:04:24 +05:30 committed by GitHub
parent 49d67899be
commit 096a0081e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 111 additions and 18 deletions

View File

@ -0,0 +1 @@
@cerc-io:registry=https://git.vdb.to/api/packages/cerc-io/npm/

View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint

View File

@ -57,6 +57,13 @@ const main = async (): Promise<void> => {
describe: 'Continue generating watcher if unhandled types encountered',
type: 'boolean'
})
.option('overwrite', {
alias: 'o',
demandOption: false,
default: false,
describe: 'Overwrite previously generated watcher',
type: 'boolean'
})
.argv;
const config = getConfig(path.resolve(argv['config-file']));
@ -108,11 +115,13 @@ const main = async (): Promise<void> => {
}
const continueOnError = argv['continue-on-error'];
const overwriteExisting = argv.overwrite;
const visitor = new Visitor(continueOnError);
parseAndVisit(visitor, contracts, config.mode);
generateWatcher(visitor, contracts, config);
generateWatcher(visitor, contracts, config, overwriteExisting);
};
function parseAndVisit (visitor: Visitor, contracts: any[], mode: string) {
@ -148,12 +157,23 @@ function parseAndVisit (visitor: Visitor, contracts: any[], mode: string) {
}
}
function generateWatcher (visitor: Visitor, contracts: any[], config: any) {
function generateWatcher (visitor: Visitor, contracts: any[], config: any, overWriteExisting = false) {
// Prepare directory structure for the watcher.
let outputDir = '';
if (config.outputFolder) {
outputDir = path.resolve(config.outputFolder);
if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
if (fs.existsSync(outputDir)) {
if (!overWriteExisting) {
throw new Error('Watcher already exists in output folder. Run with --overwrite flag to overwrite');
}
} else {
fs.mkdirSync(outputDir, { recursive: true });
}
const huskyDir = path.join(outputDir, '.husky');
if (!fs.existsSync(huskyDir)) fs.mkdirSync(huskyDir);
const environmentsFolder = path.join(outputDir, 'environments');
if (!fs.existsSync(environmentsFolder)) fs.mkdirSync(environmentsFolder);
@ -247,6 +267,23 @@ function generateWatcher (visitor: Visitor, contracts: any[], config: any) {
: process.stdout;
writeFileToStream(path.join(ASSET_DIR, '.gitignore'), outStream);
outStream = outputDir
? fs.createWriteStream(path.join(outputDir, '.npmrc'))
: process.stdout;
writeFileToStream(path.join(ASSET_DIR, '.npmrc'), outStream);
const huskyPreCommitFilePath = path.join(outputDir, '.husky/pre-commit');
outStream = outputDir
? fs.createWriteStream(huskyPreCommitFilePath)
: process.stdout;
writeFileToStream(path.join(ASSET_DIR, 'pre-commit'), outStream);
if (fs.existsSync(huskyPreCommitFilePath)) {
// Set file permission to executable
fs.chmodSync(huskyPreCommitFilePath, '775');
}
outStream = outputDir
? fs.createWriteStream(path.join(outputDir, 'src/job-runner.ts'))
: process.stdout;

View File

@ -22,11 +22,15 @@ export class Indexer {
_events: Array<any>;
_subgraphEntities: Array<any>;
_templateString: string;
_hasStateVariableElementaryType: boolean;
_hasStateVariableMappingType: boolean;
constructor () {
this._queries = [];
this._events = [];
this._subgraphEntities = [];
this._hasStateVariableElementaryType = false;
this._hasStateVariableMappingType = false;
this._templateString = fs.readFileSync(path.resolve(__dirname, TEMPLATE_FILE)).toString();
}
@ -92,6 +96,15 @@ export class Indexer {
if (stateVariableType) {
queryObject.stateVariableType = stateVariableType;
switch (stateVariableType) {
case 'ElementaryTypeName':
this._hasStateVariableElementaryType = true;
break;
case 'Mapping':
this._hasStateVariableMappingType = true;
break;
}
}
this._queries.push(queryObject);
@ -173,6 +186,8 @@ export class Indexer {
contracts,
queries: this._queries,
subgraphEntities: this._subgraphEntities,
hasStateVariableElementaryType: this._hasStateVariableElementaryType,
hasStateVariableMappingType: this._hasStateVariableMappingType,
constants: {
MODE_ETH_CALL,
MODE_STORAGE

View File

@ -257,7 +257,12 @@ export class Schema {
value: (isArray) ? `[${value}]!` : value,
proof: () => this._composer.getOTC('Proof')
});
});
}
);
// Using this to declare result types before queries
this._composer.addSchemaMustHaveType(typeComposer);
return typeComposer;
}

View File

@ -37,7 +37,7 @@ export const SUBGRAPH_ENTITIES = new Set([
{{~/each}}]);
{{/if}}
export const ENTITIES = [
{{~#each queries as | query |}}{{~#if @index }}, {{/if}}{{query.entityName}}{{/each}}
{{~#each queries as | query |}}{{query.entityName}}{{#unless @last}}, {{/unless}}{{/each}}{{#if (subgraphPath)}}, {{/if}}
{{~#if (subgraphPath)}}...SUBGRAPH_ENTITIES{{/if}}];
{{#if (subgraphPath)}}
// Map: Entity to suitable query type.

View File

@ -4,7 +4,13 @@
import assert from 'assert';
import { updateStateForMappingType, updateStateForElementaryType, ResultEvent } from '@cerc-io/util';
import {
ResultEvent,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
updateStateForMappingType,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
updateStateForElementaryType
} from '@cerc-io/util';
import { Indexer } from './indexer';

View File

@ -3,9 +3,11 @@
//
import assert from 'assert';
import { DeepPartial, FindConditions, FindManyOptions{{#if (subgraphPath)}}, ObjectLiteral{{/if}} } from 'typeorm';
import debug from 'debug';
import { DeepPartial, FindConditions, FindManyOptions, ObjectLiteral } from 'typeorm';
{{#if queries}}
import JSONbig from 'json-bigint';
{{/if}}
import { ethers } from 'ethers';
{{#if (subgraphPath)}}
import { SelectionNode } from 'graphql';
@ -23,8 +25,12 @@ import {
JobQueue,
Where,
QueryOptions,
{{#if hasStateVariableElementaryType}}
updateStateForElementaryType,
{{/if}}
{{#if hasStateVariableMappingType}}
updateStateForMappingType,
{{/if}}
{{#if (subgraphPath)}}
BlockHeight,
updateSubgraphState,
@ -53,15 +59,21 @@ import { SyncStatus } from './entity/SyncStatus';
import { StateSyncStatus } from './entity/StateSyncStatus';
import { BlockProgress } from './entity/BlockProgress';
import { State } from './entity/State';
{{#if (subgraphPath)}}
/* eslint-disable @typescript-eslint/no-unused-vars */
{{#each subgraphEntities as | subgraphEntity |}}
import { {{subgraphEntity.className}} } from './entity/{{subgraphEntity.className}}';
{{/each}}
{{#if (subgraphPath)}}
/* eslint-enable @typescript-eslint/no-unused-vars */
import { FrothyEntity } from './entity/FrothyEntity';
{{/if}}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const log = debug('vulcanize:indexer');
{{#if queries}}
const JSONbigNative = JSONbig({ useNativeBigInt: true });
{{/if}}
{{#each contracts as | contract |}}
const KIND_{{capitalize contract.contractName}} = '{{contract.contractKind}}';
@ -178,12 +190,12 @@ export class Indexer implements IndexerInterface {
};
}
{{/unless}}
log('{{query.name}}: db miss, fetching from upstream server');
const { block: { number } } = await this._ethClient.getBlockByHash(blockHash);
const blockNumber = ethers.BigNumber.from(number).toNumber();
{{/unless}}
log('{{query.name}}: db miss, fetching from upstream server');
{{#if (compare query.mode @root.constants.MODE_ETH_CALL)}}
const abi = this._abiMap.get(KIND_{{capitalize query.contract}});
assert(abi);
@ -279,7 +291,7 @@ export class Indexer implements IndexerInterface {
return createStateCheckpoint(this, contractAddress, blockHash);
}
async processCanonicalBlock (blockHash: string, blockNumber: number): Promise<void> {
async processCanonicalBlock (blockHash: string{{~#if (subgraphPath)}}, blockNumber: number{{/if}}): Promise<void> {
console.time('time:indexer#processCanonicalBlock-finalize_auto_diffs');
// Finalize staged diff blocks if any.
await this._baseIndexer.finalizeDiffStaged(blockHash);

View File

@ -8,6 +8,7 @@
"lint": "eslint --max-warnings=0 .",
"build": "yarn clean && tsc && yarn copy-assets",
"clean": "rm -rf ./dist",
"prepare": "husky install",
"copy-assets": "copyfiles -u 1 src/**/*.gql dist/",
"server": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true node --enable-source-maps dist/server.js",
"server:dev": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true ts-node src/server.ts",
@ -72,6 +73,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"husky": "^7.0.2",
"ts-node": "^10.2.1",
"typescript": "^5.0.2",
"copyfiles": "^2.4.1"

View File

@ -6,18 +6,26 @@ import assert from 'assert';
import BigInt from 'apollo-type-bigint';
import debug from 'debug';
import Decimal from 'decimal.js';
import { GraphQLResolveInfo, GraphQLScalarType } from 'graphql';
import {
GraphQLScalarType,
GraphQLResolveInfo
} from 'graphql';
import {
{{#if queries}}
ValueResult,
BlockHeight,
{{/if}}
gqlTotalQueryCount,
gqlQueryCount,
jsonBigIntStringReplacer,
getResultState,
setGQLCacheHints,
IndexerInterface,
EventWatcher
{{#if (subgraphPath)}}
BlockHeight,
jsonBigIntStringReplacer,
{{/if}}
EventWatcher,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
setGQLCacheHints
} from '@cerc-io/util';
import { Indexer } from './indexer';
@ -33,6 +41,7 @@ const log = debug('vulcanize:resolver');
export const createResolvers = async (indexerArg: IndexerInterface, eventWatcher: EventWatcher): Promise<any> => {
const indexer = indexerArg as Indexer;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const gqlCacheConfig = indexer.serverConfig.gqlCache;
return {
@ -81,7 +90,9 @@ export const createResolvers = async (indexerArg: IndexerInterface, eventWatcher
{ blockHash, contractAddress
{{~#each this.params}}, {{this.name~}} {{/each}} }: { blockHash: string, contractAddress: string
{{~#each this.params}}, {{this.name}}: {{this.type~}} {{/each}} },
// eslint-disable-next-line @typescript-eslint/no-unused-vars
__: any,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
info: GraphQLResolveInfo
): Promise<ValueResult> => {
log('{{this.name}}', blockHash, contractAddress