Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: typeFix(...) #43

Merged
merged 2 commits into from
Jan 3, 2024
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
24 changes: 14 additions & 10 deletions src/get-constructor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ContractDefinitionNode, FunctionDefinitionNode, VariableDeclarationNode } from './types';
import { typeFix } from './utils';

/**
* Return the constructor of the contract
Expand All @@ -21,31 +22,34 @@ export const getConstructor = (contractNode: ContractDefinitionNode): string =>
const parameters: VariableDeclarationNode[] = constructorNode.parameters.parameters ? constructorNode.parameters.parameters : [];

// We save the parameters in an array with their types and storage location
const mockConstructorParameters: string[] = [];
// We save the parameters names in an other array
const constructorParameters: string[] = [];
// We save the parameters names in another array
const parameterNames: string[] = [];

let parameterIndex = 0;
parameters.forEach((parameter) => {
// We remove the 'contract ' string from the type name if it exists
const typeName: string = typeFix(parameter.typeDescriptions.typeString);
const paramName: string = parameter.name == '' ? `_param${parameterIndex}` : parameter.name;

// If the storage location is memory or calldata then we keep it
const storageLocation =
parameter.storageLocation === 'memory' || parameter.storageLocation === 'calldata' ? `${parameter.storageLocation} ` : '';

// We remove the 'contract ' string from the type name if it exists
const typeName: string = parameter.typeDescriptions.typeString.replace(/contract |struct |enum /g, '');

// We create the string that will be used in the constructor signature
const parameterString = `${typeName} ${storageLocation}${parameter.name}`;
const parameterString = `${typeName} ${storageLocation}${paramName}`;

// We save the strings in the arrays
mockConstructorParameters.push(parameterString);
parameterNames.push(parameter.name);
constructorParameters.push(parameterString);
parameterNames.push(paramName);
parameterIndex++;
});

// We join the arrays with a comma and a space between them
const mockConstructorParametersString = mockConstructorParameters.join(', ');
const constructorParametersString = constructorParameters.join(', ');
const parameterNamesString = parameterNames.join(', ');

// Create the constructor signature and return it
const constructorSignature = `constructor(${mockConstructorParametersString}) ${contractName}(${parameterNamesString}) {}`;
const constructorSignature = `constructor(${constructorParametersString}) ${contractName}(${parameterNamesString}) {}`;
return constructorSignature;
};
8 changes: 5 additions & 3 deletions src/get-external-functions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ContractDefinitionNode, FunctionDefinitionNode, VariableDeclarationNode, ExternalFunctionOptions } from './types';
import { typeFix } from './utils';

/**
* Returns the information of the external function for the mock contract
Expand Down Expand Up @@ -33,7 +34,7 @@ export const getExternalMockFunctions = (contractNode: ContractDefinitionNode):
let parameterIndex = 0;
parameters.forEach((parameter: VariableDeclarationNode) => {
// We remove the 'contract ' string from the type name if it exists
const typeName: string = parameter.typeDescriptions.typeString.replace(/contract |struct |enum /g, '');
const typeName: string = typeFix(parameter.typeDescriptions.typeString);
const paramName: string = parameter.name == '' ? `_param${parameterIndex}` : parameter.name;

// If the storage location is memory or calldata then we keep it
Expand All @@ -43,6 +44,7 @@ export const getExternalMockFunctions = (contractNode: ContractDefinitionNode):
// We create the string that will be used in the constructor signature
const parameterString = `${typeName} ${storageLocation}${paramName}`;

// We save the strings in the arrays
functionParameters.push(parameterString);
parameterTypes.push(typeName);
parameterNames.push(paramName);
Expand All @@ -62,9 +64,9 @@ export const getExternalMockFunctions = (contractNode: ContractDefinitionNode):
parameterIndex = 0;
returnParameters.forEach((parameter: VariableDeclarationNode) => {
// We remove the 'contract ' string from the type name if it exists
const typeName: string = parameter.typeDescriptions.typeString.replace(/contract |struct |enum /g, '');
const typeName: string = typeFix(parameter.typeDescriptions.typeString);
const paramName: string = parameter.name == '' ? `_returnParam${parameterIndex}` : parameter.name;

// If the storage location is memory or calldata then we keep it
const storageLocation =
parameter.storageLocation === 'memory' || parameter.storageLocation === 'calldata' ? `${parameter.storageLocation} ` : '';
Expand Down
8 changes: 5 additions & 3 deletions src/get-internal-functions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ContractDefinitionNode, FunctionDefinitionNode, VariableDeclarationNode, InternalFunctionOptions } from './types';
import { typeFix } from './utils';

/**
* Returns the information of the internal function for the mock contract
Expand Down Expand Up @@ -33,7 +34,7 @@ export const getInternalMockFunctions = (contractNode: ContractDefinitionNode):
let parameterIndex = 0;
parameters.forEach((parameter: VariableDeclarationNode) => {
// We remove the 'contract ' string from the type name if it exists
const typeName: string = parameter.typeDescriptions.typeString.replace(/contract |struct |enum /g, '');
const typeName: string = typeFix(parameter.typeDescriptions.typeString);
const paramName: string = parameter.name == '' ? `_param${parameterIndex}` : parameter.name;

// If the storage location is memory or calldata then we keep it
Expand Down Expand Up @@ -64,16 +65,17 @@ export const getInternalMockFunctions = (contractNode: ContractDefinitionNode):
parameterIndex = 0;
returnParameters.forEach((parameter: VariableDeclarationNode) => {
// We remove the 'contract ' string from the type name if it exists
const typeName: string = parameter.typeDescriptions.typeString.replace(/contract |struct |enum /g, '');
const typeName: string = typeFix(parameter.typeDescriptions.typeString);
const paramName: string = parameter.name == '' ? `_returnParam${parameterIndex}` : parameter.name;

// If the storage location is memory or calldata then we keep it
const storageLocation =
parameter.storageLocation === 'memory' || parameter.storageLocation === 'calldata' ? `${parameter.storageLocation} ` : '';

// We create the string that will be used in the constructor signature
const parameterString = `${typeName} ${storageLocation}${paramName}`;

// We save the strings in the arrays
functionReturnParameters.push(parameterString);
returnParameterTypes.push(typeName);
returnParameterNames.push(paramName);
Expand Down
18 changes: 9 additions & 9 deletions src/get-variables-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
MappingStateVariableOptions,
StateVariablesOptions,
} from './types';
import { typeFix } from './utils';
import { typeFix, explicitTypeStorageLocation } from './utils';

/**
* Returns all the mock functions information for state variables
Expand Down Expand Up @@ -65,13 +65,13 @@ function getArrayFunction(arrayNode: VariableDeclarationNode): ArrayStateVariabl
const arrayName: string = arrayNode.name;

// Array type
const arrayType: string = typeFix(arrayNode.typeDescriptions.typeString).replace(/contract |struct |enum /g, '');
const arrayType: string = typeFix(explicitTypeStorageLocation(arrayNode.typeDescriptions.typeString));

// Base type
const baseType: string = typeFix(arrayNode.typeName.baseType.typeDescriptions.typeString).replace(/contract |struct |enum /g, '');
const baseType: string = typeFix(explicitTypeStorageLocation(arrayNode.typeName.baseType.typeDescriptions.typeString));

// Struct flag
const isStruct: boolean = arrayNode.typeDescriptions.typeString.includes('struct ');
const isStruct: boolean = arrayNode.typeDescriptions.typeString.startsWith('struct ');

// If the array is internal we don't create mockCall for it
const isInternal: boolean = arrayNode.visibility == 'internal';
Expand Down Expand Up @@ -112,22 +112,22 @@ function getMappingFunction(mappingNode: VariableDeclarationNode): MappingStateV
const keyTypes: string[] = [];

do {
const keyType: string = typeFix(mappingTypeNameNode.keyType.typeDescriptions.typeString).replace(/contract |struct |enum /g, '');
const keyType: string = typeFix(explicitTypeStorageLocation(mappingTypeNameNode.keyType.typeDescriptions.typeString));
keyTypes.push(keyType);
mappingTypeNameNode = mappingTypeNameNode.valueType;
} while (mappingTypeNameNode.typeDescriptions.typeString.startsWith('mapping'));

// Value type
const valueType: string = typeFix(mappingTypeNameNode.typeDescriptions.typeString).replace(/contract |struct |enum /g, '');
const valueType: string = typeFix(explicitTypeStorageLocation(mappingTypeNameNode.typeDescriptions.typeString));

// Array flag
const isArray: boolean = valueType.includes('[]');

// Base type
const baseType: string = isArray ? typeFix(mappingTypeNameNode.baseType.typeDescriptions.typeString).replace(/contract |struct |enum /g, '') : valueType;
const baseType: string = isArray ? typeFix(explicitTypeStorageLocation(mappingTypeNameNode.baseType.typeDescriptions.typeString)) : valueType;

// Struct array flag
const isStructArray: boolean = isArray && mappingTypeNameNode.typeDescriptions.typeString.includes('struct ');
const isStructArray: boolean = isArray && mappingTypeNameNode.typeDescriptions.typeString.startsWith('struct ');

// If the mapping is internal we don't create mockCall for it
const isInternal: boolean = mappingNode.visibility == 'internal';
Expand Down Expand Up @@ -164,7 +164,7 @@ function getBasicStateVariableFunction(variableNode: VariableDeclarationNode): B
const variableName: string = variableNode.name;

// remove spec type leading string
const variableType: string = typeFix(variableNode.typeDescriptions.typeString).replace(/contract |struct |enum /g, '');
const variableType: string = typeFix(explicitTypeStorageLocation(variableNode.typeDescriptions.typeString));

// If the variable is internal we don't create mockCall for it
const isInternal: boolean = variableNode.visibility == 'internal';
Expand Down
6 changes: 2 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,5 @@ export interface InternalFunctionOptions {
implemented: boolean;
}

export const memoryTypes = ['string', 'bytes', 'mapping'];

export const arrayRegex = /(\w+)\[\]/;
export const structRegex = /struct (\w+)/;
export const userDefinedTypes = ['contract', 'enum', 'struct'];
export const explicitTypes = ['string', 'bytes', 'mapping', 'struct'];
29 changes: 19 additions & 10 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { arrayRegex, memoryTypes, structRegex } from './types';
import { userDefinedTypes, explicitTypes } from './types';
import { resolve, join, relative, dirname } from 'path';
import { readFileSync, readdirSync, statSync } from 'fs';
import { exec } from 'child_process';
Expand Down Expand Up @@ -40,17 +40,26 @@ export const lowercaseFirstLetter = (str: string): string => {
};

/**
* Returns the string with the type fixed, for example if the type is string it will return `string memory`
* @param str The string to fix the type
* @returns Returns the string with the type fixed
* Fixes user-defined types
* @param type The string of the type to fix
* @returns The string with the type fixed
*/
export const typeFix = (str: string): string => {
if (memoryTypes.includes(str) || arrayRegex.exec(str)) {
return `${str} memory`;
} else if (structRegex.exec(str)) {
return `${str} memory`;
export const typeFix = (type: string): string => {
const regExp = new RegExp(`^(${userDefinedTypes.join('|')}) `);
return type.replace(regExp, '');
};

/**
* Explicits a type's storage location, if required
* @param type The string of the type to explicit
* @returns The string with the type explicit
*/
export const explicitTypeStorageLocation = (type: string): string => {
const regExp = new RegExp(`^(${explicitTypes.join('|')})\\b`);
if (regExp.test(type) || type.includes('[]')) {
return `${type} memory`;
} else {
return str;
return type;
}
};

Expand Down