Skip to content

Commit

Permalink
Move abi-codegen to common-ethereum (#2010)
Browse files Browse the repository at this point in the history
* remove redundant test files and move ethereum codegen to common-ethereum

* updated changelog

* removed typechain

* bump common-eth, update cli with common changes

* update build script to include templates, update generate test imports

* update prepack script
  • Loading branch information
bz888 authored Sep 12, 2023
1 parent b1a3886 commit bb134f9
Show file tree
Hide file tree
Showing 29 changed files with 82 additions and 1,005 deletions.
1 change: 1 addition & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update common packages version from `latest`, to ensure they will be bumped (#1992)
- Update model codegen to include `getByFields` and produce prettier code (#1993)
- migrate from `oclif` v1 to v2
- Move abi-codegen from `cli` to `common-ethereum` (#2010)

### Removed
- replaced `oclif-dev` dependency with `oclif` due to v2 migration (#1998)
Expand Down
8 changes: 3 additions & 5 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@
"@subql/common": "workspace:*",
"@subql/common-algorand": "^2.4.0",
"@subql/common-cosmos": "^2.5.0",
"@subql/common-ethereum": "^2.2.5",
"@subql/common-ethereum": "^2.3.0",
"@subql/common-flare": "^2.2.5",
"@subql/common-near": "^2.4.0",
"@subql/common-stellar": "^2.2.1-1",
"@subql/common-substrate": "workspace:*",
"@subql/utils": "workspace:*",
"@subql/validator": "workspace:*",
"@typechain/ethers-v5": "10.2.0",
"algosdk": "^1.19.0",
"boxen": "5.1.2",
"cli-ux": "^6.0.9",
Expand All @@ -36,7 +35,6 @@
"terser-webpack-plugin": "^5.3.7",
"ts-loader": "^9.2.6",
"tslib": "^2.3.1",
"typechain": "8.1.1",
"update-notifier": "5.1.0",
"webpack": "^5.76.0",
"webpack-merge": "^5.8.0",
Expand Down Expand Up @@ -81,10 +79,10 @@
]
},
"scripts": {
"build": "rm -rf lib && tsc -b",
"build": "rm -rf lib && tsc -b && cp -r src/template lib/",
"postpack": "rm -f oclif.manifest.json",
"posttest": "eslint . --ext .ts --config .eslintrc",
"prepack": "yarn build && cp -r src/template lib/ && oclif manifest && oclif readme",
"prepack": "yarn build && oclif manifest && oclif readme",
"test": "echo NO TESTS",
"version": "oclif readme && git add README.md",
"format": "prettier --write \"src/**/*.ts\""
Expand Down
126 changes: 1 addition & 125 deletions packages/cli/src/controller/codegen-controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fs from 'fs';
import path from 'path';
import rimraf from 'rimraf';
import {abiInterface, codegen, joinInputAbiName, processAbis, validateEntityName} from './codegen-controller';
import {codegen, validateEntityName} from './codegen-controller';

jest.mock('fs', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -39,128 +39,4 @@ describe('Codegen can generate schema (mocked)', () => {
'EntityName: exampleEntityFilters cannot end with reservedKey: filters'
);
});
it('read artifact abis', () => {
const projectPath = path.join(__dirname, '../../test/abiTest1');
const abisAssetObj = {
key: 'abis',
value: './abis/abis.json',
};

const artifactAssetObj = {
key: 'artifact',
value: './abis/artifact.sol/artifact.json',
};
const sortAssets_abis = new Map<string, string>();
const sortAssets_artifact = new Map<string, string>();

sortAssets_abis.set(abisAssetObj.key, abisAssetObj.value);
sortAssets_artifact.set(artifactAssetObj.key, artifactAssetObj.value);
const a = path.join(projectPath, './abis/abis.json');
const b = path.join(projectPath, './abis/artifact.sol/artifact.json');
// to mock the values for processAbi function

// mock loadFromJsonOrYaml, in Jest environment it would return undefined.
const mockLoadFromJsonOrYaml: jest.Mock<abiInterface[] | {abi: abiInterface[]}> = jest.fn();

// Conditional for which json should be implemented depending on the given path
mockLoadFromJsonOrYaml.mockImplementation((filePath: string) => {
if (filePath === a) {
return require(a);
} else if (filePath === b) {
return require(b);
}
return [];
});

const abisRendered = processAbis(sortAssets_abis, projectPath, mockLoadFromJsonOrYaml);
const artifactRendered = processAbis(sortAssets_artifact, projectPath, mockLoadFromJsonOrYaml);

// exclude name field
artifactRendered.map((e) => {
e.name = expect.any(String);
});
expect(abisRendered).toStrictEqual(expect.objectContaining(artifactRendered));
});
it('Empty abi json, should throw', () => {
const projectPath = path.join(__dirname, '../../test/abiTest2');
const artifactAssetObj = {
key: 'artifact',
value: './artifact.json',
};
const sortAssets_artifact = new Map<string, string>();

sortAssets_artifact.set(artifactAssetObj.key, artifactAssetObj.value);

const mockLoadFromJsonOrYaml: jest.Mock<abiInterface[] | {abi: abiInterface[]}> = jest.fn();

// mock loadFromJsonOrYaml, in Jest environment it would return undefined.
mockLoadFromJsonOrYaml.mockImplementation((filePath: string) => {
return [];
});

expect(() => processAbis(sortAssets_artifact, projectPath, mockLoadFromJsonOrYaml)).toThrow(
'Invalid abi is provided at asset: artifact'
);
});
it('json is object without abi field, should throw', () => {
const projectPath = path.join(__dirname, '../../test/abiTest2');
const artifactAssetObj = {
key: 'artifact',
value: './abis/artifact.json',
};
const sortAssets_artifact = new Map<string, string>();

sortAssets_artifact.set(artifactAssetObj.key, artifactAssetObj.value);

const mockLoadFromJsonOrYaml: jest.Mock<abiInterface[] | {abi: abiInterface[]}> = jest.fn();

// mock loadFromJsonOrYaml, in Jest environment it would return undefined.
mockLoadFromJsonOrYaml.mockImplementation((filePath: string) => {
return require(path.join(projectPath, artifactAssetObj.value));
});

expect(() => processAbis(sortAssets_artifact, projectPath, mockLoadFromJsonOrYaml)).toThrow(
'Provided ABI is not a valid ABI or Artifact'
);
});

it('should replace [] in input abi name', () => {
const mockAbiInterface = {
type: 'function',
name: 'initialize',
inputs: [
{
name: '__name',
type: 'string',
},
{
name: '__symbol',
type: 'string',
},
{
name: '__baseURI',
type: 'string',
},
{
name: 'admins',
type: 'address[]',
},
],
} as abiInterface;

expect(joinInputAbiName(mockAbiInterface)).toMatch('initialize_string_string_string_address_arr_');
});
it('ensure correct output when input does not contain []', () => {
const mockAbiInterface = {
type: 'function',
name: 'initialize',
inputs: [
{
name: '__name',
type: 'STRING',
},
],
} as abiInterface;
expect(joinInputAbiName(mockAbiInterface)).toMatch('initialize_string_');
});
});
35 changes: 15 additions & 20 deletions packages/cli/src/controller/codegen-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,54 @@ jest.setTimeout(30000);

describe('Codegen can generate schema', () => {
afterEach(async () => {
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest1/src'));
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest2/src'));
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest3/src'));
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest4/src'));
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest5/src'));
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest6/src'));
await promisify(rimraf)(path.join(__dirname, '../../test/schemaTest/src'));
});

it('codegen with correct schema should pass', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest1');
await codegen(projectPath);
const projectPath = path.join(__dirname, '../../test/schemaTest');
await expect(codegen(projectPath)).resolves.not.toThrow();
});

it('codegen with incorrect schema field should fail', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest2');
await expect(codegen(projectPath)).rejects.toThrow(/is not an valid type/);
const projectPath = path.join(__dirname, '../../test/schemaTest');
await expect(codegen(projectPath, ['project-bad-schema.yaml'])).rejects.toThrow(/is not an valid type/);
});
it('codegen with entities that uses reserved names should throw', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest3');
await expect(codegen(projectPath)).rejects.toThrow(
const projectPath = path.join(__dirname, '../../test/schemaTest');
await expect(codegen(projectPath, ['project-bad-entity.yaml'])).rejects.toThrow(
'EntityName: exampleEntityFilter cannot end with reservedKey: filter'
);
});
it('Codegen should be able to generate ABIs from template datasources', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest4');
await codegen(projectPath);
const projectPath = path.join(__dirname, '../../test/schemaTest');
await codegen(projectPath, ['project-templates-abi.yaml']);
await expect(
fs.promises.readFile(`${projectPath}/src/types/abi-interfaces/Erc721.ts`, 'utf8')
).resolves.toBeTruthy();
});

it('Should not fail, if ds does not have any assets', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest5');
await expect(codegen(projectPath)).resolves.not.toThrow();
const projectPath = path.join(__dirname, '../../test/schemaTest');
await expect(codegen(projectPath, ['project-no-assets.yaml'])).resolves.not.toThrow();
});
it('Codegen should be able to generate ABIs from customName datasources', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest6');
const projectPath = path.join(__dirname, '../../test/schemaTest');
await codegen(projectPath);
await expect(
fs.promises.readFile(`${projectPath}/src/types/abi-interfaces/Erc721.ts`, 'utf8')
).resolves.toBeTruthy();
});

it('Should clean out existing types directory', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest6');
const projectPath = path.join(__dirname, '../../test/schemaTest');
await codegen(projectPath);
await codegen(projectPath, ['project-no-abi.yaml']);

// should not contain abi directory
await expect(fs.promises.readFile(`${projectPath}/src/types/abi-interfaces/Erc721.ts`, 'utf8')).rejects.toThrow();
});
it('should generate contracts on different glob paths', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest6');
const projectPath = path.join(__dirname, '../../test/schemaTest');
await codegen(projectPath, ['typechain-test.yaml']);

await expect(
Expand All @@ -80,7 +75,7 @@ describe('Codegen can generate schema', () => {
).resolves.toBeTruthy();
});
it('Should not generate ABI for non evm ds', async () => {
const projectPath = path.join(__dirname, '../../test/schemaTest6');
const projectPath = path.join(__dirname, '../../test/schemaTest');
await codegen(projectPath, ['non-evm-project.yaml']);
expect(fs.existsSync(`${projectPath}/src/types/abi-interfaces/`)).toBeFalsy();
});
Expand Down
Loading

0 comments on commit bb134f9

Please sign in to comment.