Merge pull request #861 from ethereum/libsLinting

libs linting fix
pull/5370/head
yann300 4 years ago committed by GitHub
commit 31bc9d57e4
  1. 4
      libs/remix-analyzer/.eslintrc
  2. 7
      libs/remix-analyzer/src/solidity-analyzer/index.ts
  3. 26
      libs/remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts
  4. 14
      libs/remix-analyzer/src/solidity-analyzer/modules/assignAndCompare.ts
  5. 9
      libs/remix-analyzer/src/solidity-analyzer/modules/blockBlockhash.ts
  6. 18
      libs/remix-analyzer/src/solidity-analyzer/modules/blockTimestamp.ts
  7. 23
      libs/remix-analyzer/src/solidity-analyzer/modules/checksEffectsInteraction.ts
  8. 32
      libs/remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts
  9. 10
      libs/remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts
  10. 10
      libs/remix-analyzer/src/solidity-analyzer/modules/deleteFromDynamicArray.ts
  11. 19
      libs/remix-analyzer/src/solidity-analyzer/modules/erc20Decimals.ts
  12. 27
      libs/remix-analyzer/src/solidity-analyzer/modules/etherTransferInLoop.ts
  13. 14
      libs/remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts
  14. 11
      libs/remix-analyzer/src/solidity-analyzer/modules/functionCallGraph.ts
  15. 23
      libs/remix-analyzer/src/solidity-analyzer/modules/gasCosts.ts
  16. 10
      libs/remix-analyzer/src/solidity-analyzer/modules/guardConditions.ts
  17. 8
      libs/remix-analyzer/src/solidity-analyzer/modules/inlineAssembly.ts
  18. 8
      libs/remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.ts
  19. 9
      libs/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts
  20. 24
      libs/remix-analyzer/src/solidity-analyzer/modules/noReturn.ts
  21. 12
      libs/remix-analyzer/src/solidity-analyzer/modules/selfdestruct.ts
  22. 14
      libs/remix-analyzer/src/solidity-analyzer/modules/similarVariableNames.ts
  23. 95
      libs/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts
  24. 14
      libs/remix-analyzer/src/solidity-analyzer/modules/stringBytesLength.ts
  25. 10
      libs/remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts
  26. 9
      libs/remix-analyzer/src/solidity-analyzer/modules/txOrigin.ts
  27. 2
      libs/remix-analyzer/src/types.ts
  28. 3
      libs/remix-astwalker/.eslintrc
  29. 79
      libs/remix-astwalker/src/astWalker.ts
  30. 56
      libs/remix-astwalker/src/sourceMappings.ts
  31. 2
      libs/remix-debug/.eslintrc
  32. 2
      libs/remix-debug/src/debugger/debugger.ts
  33. 4
      libs/remix-debug/src/solidity-decoder/types/RefType.ts
  34. 2
      libs/remix-debug/src/solidity-decoder/types/ValueType.ts
  35. 1
      libs/remix-debug/src/trace/traceCache.ts
  36. 8
      libs/remix-lib/.eslintrc
  37. 1
      libs/remix-lib/src/util.ts
  38. 3
      libs/remix-simulator/.eslintrc
  39. 1
      libs/remix-simulator/src/genesis.ts
  40. 3
      libs/remix-simulator/src/methods/misc.ts
  41. 4
      libs/remix-simulator/src/provider.ts
  42. 3
      libs/remix-simulator/src/server.ts
  43. 5
      libs/remix-solidity/.eslintrc
  44. 3
      libs/remix-solidity/src/compiler/compiler-input.ts
  45. 2
      libs/remix-solidity/src/compiler/compiler-worker.ts
  46. 30
      libs/remix-solidity/src/compiler/compiler.ts
  47. 4
      libs/remix-solidity/src/compiler/txHelper.ts
  48. 5
      libs/remix-solidity/src/compiler/types.ts
  49. 7
      libs/remix-tests/.eslintrc
  50. 19
      libs/remix-tests/src/compiler.ts
  51. 2
      libs/remix-tests/src/fileSystem.ts
  52. 5
      libs/remix-tests/src/logger.ts
  53. 13
      libs/remix-tests/src/run.ts
  54. 7
      libs/remix-tests/src/runTestFiles.ts
  55. 23
      libs/remix-tests/src/runTestSources.ts
  56. 34
      libs/remix-tests/src/testRunner.ts
  57. 7
      libs/remix-url-resolver/.eslintrc
  58. 10
      libs/remix-url-resolver/src/resolve.ts
  59. 2
      package.json
  60. 2
      workspace.json

@ -2,7 +2,9 @@
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off"
"@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off",
"dot-notation": "off"
},
"ignorePatterns": ["!**/*"]
}

@ -9,7 +9,6 @@ type ModuleObj = {
}
export default class staticAnalysisRunner {
/**
* Run analysis (Used by IDE)
* @param compilationResult contract compilation result
@ -18,9 +17,9 @@ export default class staticAnalysisRunner {
*/
run (compilationResult: CompilationResult, toRun: number[], callback: ((reports: AnalysisReport[]) => void)): void {
const modules: ModuleObj[] = toRun.map((i) => {
const module = this.modules()[i]
const m = new module()
return { 'name': m.name, 'mod': m }
const Module = this.modules()[i]
const m = new Module()
return { name: m.name, mod: m }
})
this.runWithModuleList(compilationResult, modules, callback)
}

@ -1,9 +1,13 @@
import { getStateVariableDeclarationsFromContractNode, getInheritsFromName, getContractName,
import {
getStateVariableDeclarationsFromContractNode, getInheritsFromName, getContractName,
getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName,
getFunctionDefinitionReturnParameterPart, getCompilerVersion } from './staticAnalysisCommon'
getFunctionDefinitionReturnParameterPart, getCompilerVersion
} from './staticAnalysisCommon'
import { AstWalker } from '@remix-project/remix-astwalker'
import { FunctionDefinitionAstNode, ParameterListAstNode, ModifierDefinitionAstNode, ContractHLAst, VariableDeclarationAstNode,
FunctionHLAst, ReportObj, ReportFunction, VisitFunction, ModifierHLAst, CompilationResult } from '../../types'
import {
FunctionDefinitionAstNode, ParameterListAstNode, ModifierDefinitionAstNode, ContractHLAst, VariableDeclarationAstNode,
FunctionHLAst, ReportObj, ReportFunction, VisitFunction, ModifierHLAst, CompilationResult
} from '../../types'
type WrapFunction = ((contracts: ContractHLAst[], isSameName: boolean, version: string) => ReportObj[])
@ -48,9 +52,10 @@ export default class abstractAstView {
* @contractsOut {list} return list for high level AST view
* @return {ASTNode -> void} returns a function that can be used as visit function for static analysis modules, to build up a higher level AST view for further analysis.
*/
// eslint-disable-next-line camelcase
build_visit (relevantNodeFilter: ((node:any) => boolean)): VisitFunction {
return (node: any) => {
if (node.nodeType === "ContractDefinition") {
if (node.nodeType === 'ContractDefinition') {
this.setCurrentContract({
node: node,
functions: [],
@ -59,11 +64,11 @@ export default class abstractAstView {
inheritsFrom: [],
stateVariables: getStateVariableDeclarationsFromContractNode(node)
})
} else if (node.nodeType === "InheritanceSpecifier") {
} else if (node.nodeType === 'InheritanceSpecifier') {
const currentContract: ContractHLAst = this.getCurrentContract()
const inheritsFromName: string = getInheritsFromName(node)
currentContract.inheritsFrom.push(inheritsFromName)
} else if (node.nodeType === "FunctionDefinition") {
} else if (node.nodeType === 'FunctionDefinition') {
this.setCurrentFunction({
node: node,
relevantNodes: [],
@ -78,14 +83,14 @@ export default class abstractAstView {
this.getCurrentFunction().relevantNodes.push(item.node)
}
})
} else if (node.nodeType === "ModifierDefinition") {
} else if (node.nodeType === 'ModifierDefinition') {
this.setCurrentModifier({
node: node,
relevantNodes: [],
localVariables: this.getLocalVariables(node),
parameters: this.getLocalParameters(node)
})
} else if (node.nodeType === "ModifierInvocation") {
} else if (node.nodeType === 'ModifierInvocation') {
if (!this.isFunctionNotModifier) throw new Error('abstractAstView.js: Found modifier invocation outside of function scope.')
this.getCurrentFunction().modifierInvocations.push(node)
} else if (relevantNodeFilter(node)) {
@ -102,6 +107,7 @@ export default class abstractAstView {
}
}
// eslint-disable-next-line camelcase
build_report (wrap: WrapFunction): ReportFunction {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return (compilationResult: CompilationResult) => {
@ -176,7 +182,7 @@ export default class abstractAstView {
private getLocalVariables (funcNode: ParameterListAstNode): VariableDeclarationAstNode[] {
const locals: VariableDeclarationAstNode[] = []
new AstWalker().walkFull(funcNode, (node: any) => {
if (node.nodeType === "VariableDeclaration") locals.push(node)
if (node.nodeType === 'VariableDeclaration') locals.push(node)
return true
})
return locals

@ -1,13 +1,15 @@
import { default as category } from './categories'
import category from './categories'
import { isSubScopeWithTopLevelUnAssignedBinOp, getUnAssignedTopLevelBinOps } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, BlockAstNode, IfStatementAstNode,
WhileStatementAstNode, ForStatementAstNode, CompilationResult, ExpressionStatementAstNode, SupportedVersion} from './../../types'
import algorithm from './algorithmCategories'
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, BlockAstNode, IfStatementAstNode,
WhileStatementAstNode, ForStatementAstNode, CompilationResult, ExpressionStatementAstNode, SupportedVersion
} from './../../types'
export default class assignAndCompare implements AnalyzerModule {
warningNodes: ExpressionStatementAstNode[] = []
name = `Result not used: `
description = `The result of an operation not used`
name = 'Result not used: '
description = 'The result of an operation not used'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {

@ -1,12 +1,12 @@
import { default as category } from './categories'
import category from './categories'
import { isBlockBlockHashAccess } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, FunctionCallAstNode, SupportedVersion } from './../../types'
export default class blockBlockhash implements AnalyzerModule {
warningNodes: FunctionCallAstNode[] = []
name = `Block hash: `
description = `Can be influenced by miners`
name = 'Block hash: '
description = 'Can be influenced by miners'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -30,4 +30,3 @@ export default class blockBlockhash implements AnalyzerModule {
})
}
}

@ -1,14 +1,16 @@
import { default as category } from './categories'
import category from './categories'
import { isNowAccess, isBlockTimestampAccess, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, IdentifierAstNode,
MemberAccessAstNode, SupportedVersion} from './../../types'
import algorithm from './algorithmCategories'
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, IdentifierAstNode,
MemberAccessAstNode, SupportedVersion
} from './../../types'
export default class blockTimestamp implements AnalyzerModule {
warningNowNodes: IdentifierAstNode[] = []
warningblockTimestampNodes: MemberAccessAstNode[] = []
name = `Block timestamp: `
description = `Can be influenced by miners`
name = 'Block timestamp: '
description = 'Can be influenced by miners'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -16,8 +18,8 @@ export default class blockTimestamp implements AnalyzerModule {
}
visit (node: IdentifierAstNode | MemberAccessAstNode): void {
if (node.nodeType === "Identifier" && isNowAccess(node)) this.warningNowNodes.push(node)
else if (node.nodeType === "MemberAccess" && isBlockTimestampAccess(node)) this.warningblockTimestampNodes.push(node)
if (node.nodeType === 'Identifier' && isNowAccess(node)) this.warningNowNodes.push(node)
else if (node.nodeType === 'MemberAccess' && isBlockTimestampAccess(node)) this.warningblockTimestampNodes.push(node)
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars

@ -1,16 +1,20 @@
import { default as category } from './categories'
import { isInteraction, isEffect, isLocalCallGraphRelevantNode, getFullQuallyfiedFuncDefinitionIdent,
isWriteOnStateVariable, isStorageVariableDeclaration, getFullQualifiedFunctionCallIdent, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import {
isInteraction, isEffect, isLocalCallGraphRelevantNode, getFullQuallyfiedFuncDefinitionIdent,
isWriteOnStateVariable, isStorageVariableDeclaration, getFullQualifiedFunctionCallIdent, getCompilerVersion
} from './staticAnalysisCommon'
import algorithm from './algorithmCategories'
import { buildGlobalFuncCallGraph, resolveCallGraphSymbol, analyseCallGraph } from './functionCallGraph'
import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractHLAst, VariableDeclarationAstNode,
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractHLAst, VariableDeclarationAstNode,
FunctionHLAst, ContractCallGraph, Context, FunctionCallAstNode, AssignmentAstNode, UnaryOperationAstNode,
InlineAssemblyAstNode, ReportFunction, VisitFunction, FunctionCallGraph, SupportedVersion } from './../../types'
InlineAssemblyAstNode, ReportFunction, VisitFunction, FunctionCallGraph, SupportedVersion
} from './../../types'
export default class checksEffectsInteraction implements AnalyzerModule {
name = `Check-effects-interaction: `
description = `Potential reentrancy bugs`
name = 'Check-effects-interaction: '
description = 'Potential reentrancy bugs'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.HEURISTIC
version: SupportedVersion = {
@ -50,7 +54,7 @@ export default class checksEffectsInteraction implements AnalyzerModule {
comments += (multipleContractsWithSameName) ? 'Note: Import aliases are currently not supported by this static analysis.' : ''
warnings.push({
warning: `Potential violation of Checks-Effects-Interaction pattern in ${funcName}: Could potentially lead to re-entrancy vulnerability. ${comments}`,
location: func.node['src'],
location: func.node.src,
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#re-entrancy`
})
}
@ -92,4 +96,3 @@ export default class checksEffectsInteraction implements AnalyzerModule {
return analyseCallGraph(context.callGraph, startFuncName, context, (node: any, context: Context) => isWriteOnStateVariable(node, context.stateVariables))
}
}

@ -1,17 +1,21 @@
import { default as category } from './categories'
import { isLowLevelCall, isTransfer, isExternalDirectCall, isEffect, isLocalCallGraphRelevantNode, isSelfdestructCall,
import category from './categories'
import {
isLowLevelCall, isTransfer, isExternalDirectCall, isEffect, isLocalCallGraphRelevantNode, isSelfdestructCall,
isDeleteUnaryOperation, isPayableFunction, isConstructor, getFullQuallyfiedFuncDefinitionIdent, hasFunctionBody,
isConstantFunction, isWriteOnStateVariable, isStorageVariableDeclaration, isCallToNonConstLocalFunction,
getFullQualifiedFunctionCallIdent} from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
getFullQualifiedFunctionCallIdent
} from './staticAnalysisCommon'
import algorithm from './algorithmCategories'
import { buildGlobalFuncCallGraph, resolveCallGraphSymbol, analyseCallGraph } from './functionCallGraph'
import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractCallGraph, Context, ContractHLAst,
FunctionHLAst, VariableDeclarationAstNode, FunctionCallGraph, FunctionCallAstNode, VisitFunction, ReportFunction, SupportedVersion} from './../../types'
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractCallGraph, Context, ContractHLAst,
FunctionHLAst, VariableDeclarationAstNode, FunctionCallGraph, FunctionCallAstNode, VisitFunction, ReportFunction, SupportedVersion
} from './../../types'
export default class constantFunctions implements AnalyzerModule {
name = `Constant/View/Pure functions: `
description = `Potentially constant/view/pure functions`
name = 'Constant/View/Pure functions: '
description = 'Potentially constant/view/pure functions'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.HEURISTIC
version: SupportedVersion = {
@ -26,8 +30,8 @@ export default class constantFunctions implements AnalyzerModule {
isExternalDirectCall(node) ||
isEffect(node) ||
isLocalCallGraphRelevantNode(node) ||
node.nodeType === "InlineAssembly" ||
node.nodeType === "NewExpression" ||
node.nodeType === 'InlineAssembly' ||
node.nodeType === 'NewExpression' ||
isSelfdestructCall(node) ||
isDeleteUnaryOperation(node)
)
@ -67,13 +71,13 @@ export default class constantFunctions implements AnalyzerModule {
if (func['potentiallyshouldBeConst']) {
warnings.push({
warning: `${funcName} : Potentially should be constant/view/pure but is not. ${comments}`,
location: func.node['src'],
location: func.node.src,
more: `https://solidity.readthedocs.io/en/${version}/contracts.html#view-functions`
})
} else {
warnings.push({
warning: `${funcName} : Is constant but potentially should not be. ${comments}`,
location: func.node['src'],
location: func.node.src,
more: `https://solidity.readthedocs.io/en/${version}/contracts.html#view-functions`
})
}
@ -101,8 +105,8 @@ export default class constantFunctions implements AnalyzerModule {
isTransfer(node) ||
this.isCallOnNonConstExternalInterfaceFunction(node, context) ||
isCallToNonConstLocalFunction(node) ||
node.nodeType === "InlineAssembly" ||
node.nodeType === "NewExpression" ||
node.nodeType === 'InlineAssembly' ||
node.nodeType === 'NewExpression' ||
isSelfdestructCall(node) ||
isDeleteUnaryOperation(node)
}

@ -1,12 +1,12 @@
import { default as category } from './categories'
import category from './categories'
import { isDeleteOfDynamicArray, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, UnaryOperationAstNode, SupportedVersion } from './../../types'
export default class deleteDynamicArrays implements AnalyzerModule {
rel: UnaryOperationAstNode[] = []
name = `Delete dynamic array: `
description = `Use require/assert to ensure complete deletion`
name = 'Delete dynamic array: '
description = 'Use require/assert to ensure complete deletion'
category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -22,7 +22,7 @@ export default class deleteDynamicArrays implements AnalyzerModule {
const version = getCompilerVersion(compilationResults.contracts)
return this.rel.map((node) => {
return {
warning: `The "delete" operation when applied to a dynamically sized array in Solidity generates code to delete each of the elements contained. If the array is large, this operation can surpass the block gas limit and raise an OOG exception. Also nested dynamically sized objects can produce the same results.`,
warning: 'The "delete" operation when applied to a dynamically sized array in Solidity generates code to delete each of the elements contained. If the array is large, this operation can surpass the block gas limit and raise an OOG exception. Also nested dynamically sized objects can produce the same results.',
location: node.src,
more: `https://solidity.readthedocs.io/en/${version}/types.html#delete`
}

@ -1,12 +1,12 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { isDeleteFromDynamicArray, isMappingIndexAccess } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, UnaryOperationAstNode, SupportedVersion } from './../../types'
export default class deleteFromDynamicArray implements AnalyzerModule {
relevantNodes: UnaryOperationAstNode[] = []
name = `Delete from dynamic array: `
description = `'delete' leaves a gap in array`
name = 'Delete from dynamic array: '
description = '\'delete\' leaves a gap in array'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -21,7 +21,7 @@ export default class deleteFromDynamicArray implements AnalyzerModule {
report (compilationResults: CompilationResult): ReportObj[] {
return this.relevantNodes.map((node) => {
return {
warning: `Using "delete" on an array leaves a gap. The length of the array remains the same. If you want to remove the empty position you need to shift items manually and update the "length" property.`,
warning: 'Using "delete" on an array leaves a gap. The length of the array remains the same. If you want to remove the empty position you need to shift items manually and update the "length" property.',
location: node.src,
more: 'https://github.com/miguelmota/solidity-idiosyncrasies#examples'
}

@ -1,13 +1,15 @@
import { default as category } from './categories'
import category from './categories'
import { getFunctionDefinitionName, helpers, getDeclaredVariableName, getDeclaredVariableType } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, VisitFunction, ReportFunction, ContractHLAst,
FunctionHLAst, VariableDeclarationAstNode, SupportedVersion} from './../../types'
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, VisitFunction, ReportFunction, ContractHLAst,
FunctionHLAst, VariableDeclarationAstNode, SupportedVersion
} from './../../types'
export default class erc20Decimals implements AnalyzerModule {
name = `ERC20: `
description = `'decimals' should be 'uint8'`
name = 'ERC20: '
description = '\'decimals\' should be \'uint8\''
category: ModuleCategory = category.ERC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -38,7 +40,7 @@ export default class erc20Decimals implements AnalyzerModule {
if (decimalsVar.length > 0) {
for (const node of decimalsVar) {
warnings.push({
warning: `ERC20 contract's "decimals" variable should be "uint8" type`,
warning: 'ERC20 contract\'s "decimals" variable should be "uint8" type',
location: node.src,
more: 'https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#decimals'
})
@ -46,7 +48,7 @@ export default class erc20Decimals implements AnalyzerModule {
} else if (decimalsFun.length > 0) {
for (const fn of decimalsFun) {
warnings.push({
warning: `ERC20 contract's "decimals" function should have "uint8" as return type`,
warning: 'ERC20 contract\'s "decimals" function should have "uint8" as return type',
location: fn.node.src,
more: 'https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#decimals'
})
@ -66,4 +68,3 @@ export default class erc20Decimals implements AnalyzerModule {
funSignatures.includes('allowance(address,address)')
}
}

@ -1,13 +1,15 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { isLoop, isTransfer, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode,
WhileStatementAstNode, ExpressionStatementAstNode, SupportedVersion} from './../../types'
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode,
WhileStatementAstNode, ExpressionStatementAstNode, SupportedVersion
} from './../../types'
export default class etherTransferInLoop implements AnalyzerModule {
relevantNodes: ExpressionStatementAstNode[] = []
name = `Ether transfer in loop: `
description = `Transferring Ether in a for/while/do-while loop`
name = 'Ether transfer in loop: '
description = 'Transferring Ether in a for/while/do-while loop'
category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -17,12 +19,13 @@ export default class etherTransferInLoop implements AnalyzerModule {
visit (node: ForStatementAstNode | WhileStatementAstNode): void {
let transferNodes: ExpressionStatementAstNode[] = []
if (isLoop(node)) {
if(node.body && node.body.nodeType === 'Block')
transferNodes = node.body.statements.filter(child => ( child.nodeType === 'ExpressionStatement' &&
child.expression.nodeType === 'FunctionCall' && isTransfer(child.expression.expression)))
if (node.body && node.body.nodeType === 'Block') {
transferNodes = node.body.statements.filter(child =>
(child.nodeType === 'ExpressionStatement' &&
child.expression.nodeType === 'FunctionCall' &&
isTransfer(child.expression.expression)))
} else if (node.body && node.body.nodeType === 'ExpressionStatement' && node.body.expression.nodeType === 'FunctionCall' && isTransfer(node.body.expression.expression)) { transferNodes.push(node.body) }
// When loop body is described without braces
else if(node.body && node.body.nodeType === 'ExpressionStatement' && node.body.expression.nodeType === 'FunctionCall' && isTransfer(node.body.expression.expression))
transferNodes.push(node.body)
if (transferNodes.length > 0) {
this.relevantNodes.push(...transferNodes)
}
@ -34,7 +37,7 @@ export default class etherTransferInLoop implements AnalyzerModule {
const version = getCompilerVersion(compilationResults.contracts)
return this.relevantNodes.map((node) => {
return {
warning: `Ether payout should not be done in a loop: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. If required then make sure that number of iterations are low and you trust each address involved.`,
warning: 'Ether payout should not be done in a loop: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. If required then make sure that number of iterations are low and you trust each address involved.',
location: node.src,
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#gas-limit-and-loops`
}

@ -1,12 +1,12 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { isDynamicArrayLengthAccess, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode, SupportedVersion } from './../../types'
export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
relevantNodes: ForStatementAstNode[] = []
name = `For loop over dynamic array: `
description = `Iterations depend on dynamic array's size`
name = 'For loop over dynamic array: '
description = 'Iterations depend on dynamic array\'s size'
category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -16,9 +16,9 @@ export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
visit (node: ForStatementAstNode): void {
const { condition } = node
// Check if condition is `i < array.length - 1`
if ((condition && condition.nodeType === "BinaryOperation" && condition.rightExpression.nodeType === "BinaryOperation" && isDynamicArrayLengthAccess(condition.rightExpression.leftExpression)) ||
if ((condition && condition.nodeType === 'BinaryOperation' && condition.rightExpression.nodeType === 'BinaryOperation' && isDynamicArrayLengthAccess(condition.rightExpression.leftExpression)) ||
// or condition is `i < array.length`
(condition && condition.nodeType === "BinaryOperation" && isDynamicArrayLengthAccess(condition.rightExpression))) {
(condition && condition.nodeType === 'BinaryOperation' && isDynamicArrayLengthAccess(condition.rightExpression))) {
this.relevantNodes.push(node)
}
}
@ -28,7 +28,7 @@ export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
const version = getCompilerVersion(compilationResults.contracts)
return this.relevantNodes.map((node) => {
return {
warning: `Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully. Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. \n Additionally, using unbounded loops incurs in a lot of avoidable gas costs. Carefully test how many items at maximum you can pass to such functions to make it successful.`,
warning: 'Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully. Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. \n Additionally, using unbounded loops incurs in a lot of avoidable gas costs. Carefully test how many items at maximum you can pass to such functions to make it successful.',
location: node.src,
more: `https://solidity.readthedocs.io/en/${version}/security-considerations.html#gas-limit-and-loops`
}

@ -1,8 +1,10 @@
'use strict'
import { FunctionHLAst, ContractHLAst, FunctionCallGraph, ContractCallGraph, Context, FunctionCallAstNode } from "../../types"
import { isLocalCallGraphRelevantNode, isExternalDirectCall, getFullQualifiedFunctionCallIdent,
getFullQuallyfiedFuncDefinitionIdent, getContractName } from './staticAnalysisCommon'
import { FunctionHLAst, ContractHLAst, FunctionCallGraph, ContractCallGraph, Context, FunctionCallAstNode } from '../../types'
import {
isLocalCallGraphRelevantNode, isExternalDirectCall, getFullQualifiedFunctionCallIdent,
getFullQuallyfiedFuncDefinitionIdent, getContractName
} from './staticAnalysisCommon'
type filterNodesFunction = (node: FunctionCallAstNode) => boolean
type NodeIdentFunction = (node: FunctionCallAstNode) => string
@ -108,6 +110,5 @@ function resolveCallGraphSymbolInternal (callGraph: Record<string, ContractCallG
throw new Error('functionCallGraph.js: function does not have full qualified name.')
}
if (current === undefined && !silent) console.log(`static analysis functionCallGraph.js: ${funcName} not found in function call graph.`)
if(current !== null)
return current
if (current !== null) { return current }
}

@ -1,12 +1,14 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { getFunctionDefinitionName, helpers, isVariableTurnedIntoGetter, getMethodParamsSplittedTypeDesc } from './staticAnalysisCommon'
import { ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, CompiledContract, AnalyzerModule,
FunctionDefinitionAstNode, VariableDeclarationAstNode, SupportedVersion } from './../../types'
import {
ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, CompiledContract, AnalyzerModule,
FunctionDefinitionAstNode, VariableDeclarationAstNode, SupportedVersion
} from './../../types'
export default class gasCosts implements AnalyzerModule {
name = `Gas costs: `
description = `Too high gas requirement of functions`
name = 'Gas costs: '
description = 'Too high gas requirement of functions'
category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -16,20 +18,17 @@ export default class gasCosts implements AnalyzerModule {
warningNodes: any[] = []
visit (node: FunctionDefinitionAstNode | VariableDeclarationAstNode): void {
if ((node.nodeType === 'FunctionDefinition' && node.kind !== 'constructor' && node.implemented) ||
(node.nodeType === 'VariableDeclaration' && isVariableTurnedIntoGetter(node)))
this.warningNodes.push(node)
(node.nodeType === 'VariableDeclaration' && isVariableTurnedIntoGetter(node))) { this.warningNodes.push(node) }
}
report (compilationResults: CompilationResult): ReportObj[] {
const report: ReportObj[] = []
const methodsWithSignature: Record<string, string>[] = this.warningNodes.map(node => {
let signature: string;
let signature: string
if (node.nodeType === 'FunctionDefinition') {
const functionName: string = getFunctionDefinitionName(node)
signature = helpers.buildAbiSignature(functionName, getMethodParamsSplittedTypeDesc(node, compilationResults.contracts))
}
else
signature = node.name + '()'
} else { signature = node.name + '()' }
return {
name: node.name,

@ -1,12 +1,12 @@
import { default as category } from './categories'
import category from './categories'
import { isRequireCall, isAssertCall, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, FunctionCallAstNode, SupportedVersion } from './../../types'
export default class guardConditions implements AnalyzerModule {
guards: FunctionCallAstNode[] = []
name = `Guard conditions: `
description = `Ensure appropriate use of require/assert`
name = 'Guard conditions: '
description = 'Ensure appropriate use of require/assert'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -22,7 +22,7 @@ export default class guardConditions implements AnalyzerModule {
const version = getCompilerVersion(compilationResults.contracts)
return this.guards.map((node) => {
return {
warning: `Use "assert(x)" if you never ever want x to be false, not in any circumstance (apart from a bug in your code). Use "require(x)" if x can be false, due to e.g. invalid input or a failing external component.`,
warning: 'Use "assert(x)" if you never ever want x to be false, not in any circumstance (apart from a bug in your code). Use "require(x)" if x can be false, due to e.g. invalid input or a failing external component.',
location: node.src,
more: `https://solidity.readthedocs.io/en/${version}/control-structures.html#error-handling-assert-require-revert-and-exceptions`
}

@ -1,12 +1,12 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, InlineAssemblyAstNode, SupportedVersion } from './../../types'
import { getCompilerVersion } from './staticAnalysisCommon'
export default class inlineAssembly implements AnalyzerModule {
inlineAssNodes: InlineAssemblyAstNode[] = []
name = `Inline assembly: `
description = `Inline assembly used`
name = 'Inline assembly: '
description = 'Inline assembly used'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {

@ -1,12 +1,12 @@
import { default as category } from './categories'
import category from './categories'
import { isIntDivision } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, BinaryOperationAstNode, SupportedVersion } from './../../types'
export default class intDivisionTruncate implements AnalyzerModule {
warningNodes: BinaryOperationAstNode[] = []
name = `Data truncated: `
description = `Division on int/uint values truncates the result`
name = 'Data truncated: '
description = 'Division on int/uint values truncates the result'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {

@ -1,6 +1,6 @@
import { default as category } from './categories'
import category from './categories'
import { isLLCall, isLLDelegatecall, isLLCallcode, isLLCall04, isLLDelegatecall04, isLLSend04, isLLSend, lowLevelCallTypes, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, SupportedVersion } from './../../types'
interface llcNode {
@ -10,8 +10,8 @@ interface llcNode {
export default class lowLevelCalls implements AnalyzerModule {
llcNodes: llcNode[] = []
name = `Low level calls: `
description = `Should only be used by experienced devs`
name = 'Low level calls: '
description = 'Should only be used by experienced devs'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -73,4 +73,3 @@ export default class lowLevelCalls implements AnalyzerModule {
})
}
}

@ -1,13 +1,15 @@
import { default as category } from './categories'
import category from './categories'
import { hasFunctionBody, getFullQuallyfiedFuncDefinitionIdent, getEffectedVariableName } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractHLAst, FunctionHLAst,
VisitFunction, ReportFunction, ReturnAstNode, AssignmentAstNode, SupportedVersion} from './../../types'
import {
AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractHLAst, FunctionHLAst,
VisitFunction, ReportFunction, ReturnAstNode, AssignmentAstNode, SupportedVersion
} from './../../types'
export default class noReturn implements AnalyzerModule {
name = `No return: `
description = `Function with 'returns' not returning`
name = 'No return: '
description = 'Function with \'returns\' not returning'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -17,7 +19,7 @@ export default class noReturn implements AnalyzerModule {
abstractAst: AbstractAst = new AbstractAst()
visit: VisitFunction = this.abstractAst.build_visit(
(node: ReturnAstNode | AssignmentAstNode) => node.nodeType === "Return" || node.nodeType === "Assignment"
(node: ReturnAstNode | AssignmentAstNode) => node.nodeType === 'Return' || node.nodeType === 'Assignment'
)
report: ReportFunction = this.abstractAst.build_report(this._report.bind(this))
@ -30,12 +32,12 @@ export default class noReturn implements AnalyzerModule {
if (this.hasNamedAndUnnamedReturns(func)) {
warnings.push({
warning: `${funcName}: Mixing of named and unnamed return parameters is not advised.`,
location: func.node['src']
location: func.node.src
})
} else if (this.shouldReturn(func) && !(this.hasReturnStatement(func) || (this.hasNamedReturns(func) && this.hasAssignToAllNamedReturns(func)))) {
warnings.push({
warning: `${funcName}: Defines a return type but never explicitly returns a value.`,
location: func.node['src']
location: func.node.src
})
}
})
@ -48,12 +50,12 @@ export default class noReturn implements AnalyzerModule {
}
private hasReturnStatement (func: FunctionHLAst): boolean {
return func.relevantNodes.filter(n => n.nodeType === "Return").length > 0
return func.relevantNodes.filter(n => n.nodeType === 'Return').length > 0
}
private hasAssignToAllNamedReturns (func: FunctionHLAst): boolean {
const namedReturns: string[] = func.returns.filter(n => n.name.length > 0).map((n) => n.name)
const assignedVars: string[] = func.relevantNodes.filter(n => n.nodeType === "Assignment").map(getEffectedVariableName)
const assignedVars: string[] = func.relevantNodes.filter(n => n.nodeType === 'Assignment').map(getEffectedVariableName)
const diff: string[] = namedReturns.filter(e => !assignedVars.includes(e))
return diff.length === 0
}

@ -1,12 +1,12 @@
import { default as category } from './categories'
import category from './categories'
import { isStatement, isSelfdestructCall } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, ContractHLAst, VisitFunction, ReportFunction, SupportedVersion } from './../../types'
export default class selfdestruct implements AnalyzerModule {
name = `Selfdestruct: `
description = `Contracts using destructed contract can be broken`
name = 'Selfdestruct: '
description = 'Contracts using destructed contract can be broken'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.HEURISTIC
version: SupportedVersion = {
@ -30,7 +30,7 @@ export default class selfdestruct implements AnalyzerModule {
func.relevantNodes.forEach((node) => {
if (isSelfdestructCall(node)) {
warnings.push({
warning: `Use of selfdestruct: Can block calling contracts unexpectedly. Be especially careful if this contract is planned to be used by other contracts (i.e. library contracts, interactions). Selfdestruction of the callee contract can leave callers in an inoperable state.`,
warning: 'Use of selfdestruct: Can block calling contracts unexpectedly. Be especially careful if this contract is planned to be used by other contracts (i.e. library contracts, interactions). Selfdestruction of the callee contract can leave callers in an inoperable state.',
location: node.src,
more: 'https://paritytech.io/blog/security-alert.html'
})
@ -38,7 +38,7 @@ export default class selfdestruct implements AnalyzerModule {
}
if (isStatement(node) && hasSelf) {
warnings.push({
warning: `Use of selfdestruct: No code after selfdestruct is executed. Selfdestruct is a terminal.`,
warning: 'Use of selfdestruct: No code after selfdestruct is executed. Selfdestruct is a terminal.',
location: node.src,
more: `https://solidity.readthedocs.io/en/${version}/introduction-to-smart-contracts.html#deactivate-and-self-destruct`
})

@ -1,6 +1,6 @@
import { default as category } from './categories'
import category from './categories'
import { getDeclaredVariableName, getFullQuallyfiedFuncDefinitionIdent } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import AbstractAst from './abstractAstView'
import { get } from 'fast-levenshtein'
import { util } from '@remix-project/remix-lib'
@ -14,8 +14,8 @@ interface SimilarRecord {
}
export default class similarVariableNames implements AnalyzerModule {
name = `Similar variable names: `
description = `Variable names are too similar`
name = 'Similar variable names: '
description = 'Variable names are too similar'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -53,11 +53,11 @@ export default class similarVariableNames implements AnalyzerModule {
// Walk through all statements of function
astWalker.walk(functionBody, (node) => {
// check if these is an identifier node which is one of the tracked similar variables
if ((node.nodeType === 'Identifier' || node.nodeType === 'VariableDeclaration')
&& (node.name === sim.var1 || node.name === sim.var2)) {
if ((node.nodeType === 'Identifier' || node.nodeType === 'VariableDeclaration') &&
(node.name === sim.var1 || node.name === sim.var2)) {
warnings.push({
warning: `${funcName} : Variables have very similar names "${sim.var1}" and "${sim.var2}". ${hasModifiersComments} ${multipleContractsWithSameNameComments}`,
location: node['src']
location: node.src
})
}
return true

@ -1,9 +1,11 @@
'use strict'
import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, ForStatementAstNode,
import {
FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, ForStatementAstNode,
WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode,
MemberAccessAstNode, BinaryOperationAstNode, FunctionCallAstNode, ExpressionStatementAstNode, UnaryOperationAstNode,
IdentifierAstNode, IndexAccessAstNode, BlockAstNode, AssignmentAstNode, InlineAssemblyAstNode, IfStatementAstNode, CompiledContractObj, ABIParameter, CompiledContract } from "../../types"
IdentifierAstNode, IndexAccessAstNode, BlockAstNode, AssignmentAstNode, InlineAssemblyAstNode, IfStatementAstNode, CompiledContractObj, ABIParameter, CompiledContract
} from '../../types'
import { util } from '@remix-project/remix-lib'
type SpecialObjDetail = {
@ -334,7 +336,7 @@ function getDeclaredVariableType (varDeclNode: VariableDeclarationAstNode): stri
* @return {list variable declaration} state variable node list
*/
function getStateVariableDeclarationsFromContractNode (contractNode: ContractDefinitionAstNode): VariableDeclarationAstNode[] {
return contractNode.nodes.filter(el => el.nodeType === "VariableDeclaration")
return contractNode.nodes.filter(el => el.nodeType === 'VariableDeclaration')
}
/**
@ -398,8 +400,7 @@ function getFunctionCallTypeParameterType (func: FunctionCallAstNode): string |
function getLibraryCallContractName (node: FunctionCallAstNode): string | undefined {
if (!isLibraryCall(node.expression)) throw new Error('staticAnalysisCommon.js: not a library call Node')
const types: RegExpExecArray | null = new RegExp(basicRegex.LIBRARYTYPE).exec(node.expression.expression.typeDescriptions.typeString)
if(types)
return types[1]
if (types) { return types[1] }
}
/**
@ -444,19 +445,14 @@ function getFullQuallyfiedFuncDefinitionIdent (contract: ContractDefinitionAstNo
function getUnAssignedTopLevelBinOps (subScope: BlockAstNode | IfStatementAstNode | WhileStatementAstNode | ForStatementAstNode): ExpressionStatementAstNode[] {
let result: ExpressionStatementAstNode[] = []
if(subScope && subScope.nodeType === 'Block')
result = subScope.statements.filter(isBinaryOpInExpression)
if (subScope && subScope.nodeType === 'Block') result = subScope.statements.filter(isBinaryOpInExpression)
// for 'without braces' loops
else if (subScope && subScope.nodeType && subScope.nodeType !== 'Block' && isSubScopeStatement(subScope)) {
if (subScope.nodeType === 'IfStatement') {
if((subScope.trueBody && subScope.trueBody.nodeType === "ExpressionStatement" && isBinaryOpInExpression(subScope.trueBody)))
result.push(subScope.trueBody)
if (subScope.falseBody && subScope.falseBody.nodeType === "ExpressionStatement" && isBinaryOpInExpression(subScope.falseBody))
result.push(subScope.falseBody)
}
else {
if(subScope.body && subScope.body.nodeType === "ExpressionStatement" && isBinaryOpInExpression(subScope.body))
result.push(subScope.body)
if ((subScope.trueBody && subScope.trueBody.nodeType === 'ExpressionStatement' && isBinaryOpInExpression(subScope.trueBody))) { result.push(subScope.trueBody) }
if (subScope.falseBody && subScope.falseBody.nodeType === 'ExpressionStatement' && isBinaryOpInExpression(subScope.falseBody)) { result.push(subScope.falseBody) }
} else {
if (subScope.body && subScope.body.nodeType === 'ExpressionStatement' && isBinaryOpInExpression(subScope.body)) { result.push(subScope.body) }
}
}
return result
@ -466,7 +462,7 @@ function getUnAssignedTopLevelBinOps (subScope: BlockAstNode | IfStatementAstNod
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function isStatement (node: any): boolean {
return nodeType(node, 'Statement$') || node.nodeType === "Block" || node.nodeType === "Return"
return nodeType(node, 'Statement$') || node.nodeType === 'Block' || node.nodeType === 'Return'
}
// #################### Complex Node Identification
@ -505,7 +501,7 @@ function isDynamicArrayAccess (node: IdentifierAstNode): boolean {
*/
function isDynamicArrayLengthAccess (node: MemberAccessAstNode): boolean {
return (node.memberName === 'length') && // accessing 'length' member
node.expression['typeDescriptions']['typeString'].indexOf('[]') !== -1 // member is accessed from dynamic array, notice [] without any number
node.expression.typeDescriptions.typeString.indexOf('[]') !== -1 // member is accessed from dynamic array, notice [] without any number
}
/**
@ -608,9 +604,9 @@ function isInteraction (node: FunctionCallAstNode): boolean {
* @return {bool}
*/
function isEffect (node: AssignmentAstNode | UnaryOperationAstNode | InlineAssemblyAstNode): boolean {
return node.nodeType === "Assignment" ||
(node.nodeType === "UnaryOperation" && (isPlusPlusUnaryOperation(node) || isMinusMinusUnaryOperation(node))) ||
node.nodeType === "InlineAssembly"
return node.nodeType === 'Assignment' ||
(node.nodeType === 'UnaryOperation' && (isPlusPlusUnaryOperation(node) || isMinusMinusUnaryOperation(node))) ||
node.nodeType === 'InlineAssembly'
}
/**
@ -620,7 +616,7 @@ function isEffect (node: AssignmentAstNode | UnaryOperationAstNode | InlineAssem
* @return {bool}
*/
function isWriteOnStateVariable (effectNode: AssignmentAstNode | InlineAssemblyAstNode | UnaryOperationAstNode, stateVariables: VariableDeclarationAstNode[]): boolean {
return effectNode.nodeType === "InlineAssembly" || (isEffect(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables))
return effectNode.nodeType === 'InlineAssembly' || (isEffect(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables))
}
/**
@ -648,7 +644,7 @@ function isConstantFunction (node: FunctionDefinitionAstNode): boolean {
* @return {bool}
*/
function isVariableTurnedIntoGetter (varDeclNode: VariableDeclarationAstNode): boolean {
return varDeclNode.stateVariable && varDeclNode.visibility === 'public';
return varDeclNode.stateVariable && varDeclNode.visibility === 'public'
}
/**
@ -666,7 +662,7 @@ function isPayableFunction (node: FunctionDefinitionAstNode): boolean {
* @return {bool}
*/
function isConstructor (node: FunctionDefinitionAstNode): boolean {
return node.kind === "constructor"
return node.kind === 'constructor'
}
/**
@ -684,24 +680,21 @@ function isIntDivision (node: BinaryOperationAstNode): boolean {
* @return {bool}
*/
function isSubScopeWithTopLevelUnAssignedBinOp (node: BlockAstNode | IfStatementAstNode | WhileStatementAstNode | ForStatementAstNode): boolean | undefined {
if(node.nodeType === 'Block')
return node.statements.some(isBinaryOpInExpression)
if (node.nodeType === 'Block') return node.statements.some(isBinaryOpInExpression)
// for 'without braces' loops
else if (node && node.nodeType && isSubScopeStatement(node)) {
if (node.nodeType === 'IfStatement')
return (node.trueBody && node.trueBody.nodeType === "ExpressionStatement" && isBinaryOpInExpression(node.trueBody)) ||
(node.falseBody && node.falseBody.nodeType === "ExpressionStatement" && isBinaryOpInExpression(node.falseBody))
else
return node.body && node.body.nodeType === "ExpressionStatement" && isBinaryOpInExpression(node.body)
if (node.nodeType === 'IfStatement') {
return (node.trueBody && node.trueBody.nodeType === 'ExpressionStatement' && isBinaryOpInExpression(node.trueBody)) ||
(node.falseBody && node.falseBody.nodeType === 'ExpressionStatement' && isBinaryOpInExpression(node.falseBody))
} else { return node.body && node.body.nodeType === 'ExpressionStatement' && isBinaryOpInExpression(node.body) }
}
}
function isSubScopeStatement (node: IfStatementAstNode | WhileStatementAstNode | ForStatementAstNode): boolean {
if(node.nodeType === 'IfStatement')
if (node.nodeType === 'IfStatement') {
return (node.trueBody && node.trueBody.nodeType && !nodeType(node.trueBody, exactMatch(nodeTypes.BLOCK))) ||
(node.falseBody && node.falseBody.nodeType && !nodeType(node.falseBody, exactMatch(nodeTypes.BLOCK)))
else
return node.body && node.body.nodeType && !nodeType(node.body, exactMatch(nodeTypes.BLOCK))
} else { return node.body && node.body.nodeType && !nodeType(node.body, exactMatch(nodeTypes.BLOCK)) }
}
/**
@ -710,7 +703,7 @@ function isSubScopeStatement (node: IfStatementAstNode | WhileStatementAstNode |
* @return {bool}
*/
function isBinaryOpInExpression (node: ExpressionStatementAstNode): boolean {
return node.nodeType === "ExpressionStatement" && node.expression.nodeType === "BinaryOperation"
return node.nodeType === 'ExpressionStatement' && node.expression.nodeType === 'BinaryOperation'
}
/**
@ -791,7 +784,7 @@ function isExternalDirectCall (node: FunctionCallAstNode): boolean {
* @return {bool}
*/
function isNowAccess (node: IdentifierAstNode): boolean {
return node.name === "now" && typeDescription(node, exactMatch(basicTypes.UINT))
return node.name === 'now' && typeDescription(node, exactMatch(basicTypes.UINT))
}
/**
@ -962,7 +955,7 @@ function isStringToBytesConversion (node: FunctionCallAstNode): boolean {
}
function isExplicitCast (node: FunctionCallAstNode, castFromType: string, castToType: string): boolean {
return node.kind === "typeConversion" &&
return node.kind === 'typeConversion' &&
nodeType(node.expression, exactMatch(nodeTypes.ELEMENTARYTYPENAMEEXPRESSION)) && node.expression.typeName === castToType &&
nodeType(node.arguments[0], exactMatch(nodeTypes.IDENTIFIER)) && typeDescription(node.arguments[0], castFromType)
}
@ -1053,20 +1046,7 @@ function matches (...fnArgs: any[]): string {
* Note: developed keeping identifier node search in mind to get first identifier node from left in subscope
*/
function findFirstSubNodeLTR (node: any, type: string): any {
if(node.nodeType && nodeType(node, type))
return node
else if(node.nodeType && nodeType(node, exactMatch('Assignment')))
return findFirstSubNodeLTR(node.leftHandSide, type)
else if(node.nodeType && nodeType(node, exactMatch('MemberAccess')))
return findFirstSubNodeLTR(node.expression, type)
else if(node.nodeType && nodeType(node, exactMatch('IndexAccess')))
return findFirstSubNodeLTR(node.baseExpression, type)
else if(node.nodeType && nodeType(node, exactMatch('UnaryOperation')))
return findFirstSubNodeLTR(node.subExpression, type)
if (node.nodeType && nodeType(node, type)) { return node } else if (node.nodeType && nodeType(node, exactMatch('Assignment'))) { return findFirstSubNodeLTR(node.leftHandSide, type) } else if (node.nodeType && nodeType(node, exactMatch('MemberAccess'))) { return findFirstSubNodeLTR(node.expression, type) } else if (node.nodeType && nodeType(node, exactMatch('IndexAccess'))) { return findFirstSubNodeLTR(node.baseExpression, type) } else if (node.nodeType && nodeType(node, exactMatch('UnaryOperation'))) { return findFirstSubNodeLTR(node.subExpression, type) }
}
/**
@ -1090,7 +1070,7 @@ function buildAbiSignature (funName: string, paramTypes: any[]): string {
// For address payable, return address
function getMethodParamsSplittedTypeDesc (node: FunctionDefinitionAstNode, contracts: CompiledContractObj): string[] {
return node.parameters.parameters.map((varNode, varIndex) => {
let finalTypeString;
let finalTypeString
const typeString = varNode.typeDescriptions.typeString
if (typeString.includes('struct')) {
const fnName = node.name
@ -1107,8 +1087,7 @@ function getMethodParamsSplittedTypeDesc(node: FunctionDefinitionAstNode, contra
}
}
}
} else
finalTypeString = typeString.split(' ')[0]
} else { finalTypeString = typeString.split(' ')[0] }
return finalTypeString
})
}
@ -1120,12 +1099,9 @@ function getTypeStringFromComponents(components: ABIParameter[]) {
if (param.type.includes('tuple') && param.components && param.components.length > 0) {
typeString = typeString + getTypeStringFromComponents(param.components)
typeString = typeString + param.type.replace('tuple', '')
}
else
typeString = typeString + param.type
} else { typeString = typeString + param.type }
if(i !== components.length - 1)
typeString = typeString + ','
if (i !== components.length - 1) { typeString = typeString + ',' }
}
typeString = typeString + ')'
return typeString
@ -1146,8 +1122,7 @@ function getCompilerVersion(contractFiles: CompiledContractObj): string {
if (contract && contract.metadata) {
const metadata = JSON.parse(contract.metadata)
const compilerVersion: string = metadata.compiler.version
if(!compilerVersion.includes('nightly'))
version = 'v' + compilerVersion.split('+commit')[0]
if (!compilerVersion.includes('nightly')) { version = 'v' + compilerVersion.split('+commit')[0] }
}
return version
}

@ -1,11 +1,11 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { isStringToBytesConversion, isBytesLengthCheck, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, FunctionCallAstNode, SupportedVersion } from './../../types'
export default class stringBytesLength implements AnalyzerModule {
name = `String length: `
description = `Bytes length != String length`
name = 'String length: '
description = 'Bytes length != String length'
category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -16,8 +16,8 @@ export default class stringBytesLength implements AnalyzerModule {
bytesLengthChecks: MemberAccessAstNode[] = []
visit (node: FunctionCallAstNode | MemberAccessAstNode): void {
if (node.nodeType === "FunctionCall" && isStringToBytesConversion(node)) this.stringToBytesConversions.push(node)
else if (node.nodeType === "MemberAccess" && isBytesLengthCheck(node)) this.bytesLengthChecks.push(node)
if (node.nodeType === 'FunctionCall' && isStringToBytesConversion(node)) this.stringToBytesConversions.push(node)
else if (node.nodeType === 'MemberAccess' && isBytesLengthCheck(node)) this.bytesLengthChecks.push(node)
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -25,7 +25,7 @@ export default class stringBytesLength implements AnalyzerModule {
const version = getCompilerVersion(compilationResults.contracts)
if (this.stringToBytesConversions.length > 0 && this.bytesLengthChecks.length > 0) {
return [{
warning: `"bytes" and "string" lengths are not the same since strings are assumed to be UTF-8 encoded (according to the ABI defintion) therefore one character is not nessesarily encoded in one byte of data.`,
warning: '"bytes" and "string" lengths are not the same since strings are assumed to be UTF-8 encoded (according to the ABI defintion) therefore one character is not nessesarily encoded in one byte of data.',
location: this.bytesLengthChecks[0].src,
more: `https://solidity.readthedocs.io/en/${version}/abi-spec.html#argument-encoding`
}]

@ -1,12 +1,12 @@
import { default as category } from './categories'
import category from './categories'
import { isThisLocalCall, getCompilerVersion } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories'
import algorithm from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, SupportedVersion } from './../../types'
export default class thisLocal implements AnalyzerModule {
warningNodes: MemberAccessAstNode[] = []
name = `This on local calls: `
description = `Invocation of local functions via 'this'`
name = 'This on local calls: '
description = 'Invocation of local functions via \'this\''
category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -22,7 +22,7 @@ export default class thisLocal implements AnalyzerModule {
const version = getCompilerVersion(compilationResults.contracts)
return this.warningNodes.map(function (item, i) {
return {
warning: `Use of "this" for local functions: Never use "this" to call functions in the same contract, it only consumes more gas than normal local calls.`,
warning: 'Use of "this" for local functions: Never use "this" to call functions in the same contract, it only consumes more gas than normal local calls.',
location: item.src,
more: `https://solidity.readthedocs.io/en/${version}/control-structures.html#external-function-calls`
}

@ -1,12 +1,12 @@
import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories'
import category from './categories'
import algorithm from './algorithmCategories'
import { isTxOriginAccess, getCompilerVersion } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode, SupportedVersion } from './../../types'
export default class txOrigin implements AnalyzerModule {
txOriginNodes: MemberAccessAstNode[] = []
name = `Transaction origin: `
description = `'tx.origin' used`
name = 'Transaction origin: '
description = '\'tx.origin\' used'
category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT
version: SupportedVersion = {
@ -15,7 +15,6 @@ export default class txOrigin implements AnalyzerModule {
visit (node: MemberAccessAstNode): void {
if (isTxOriginAccess(node)) this.txOriginNodes.push(node)
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars

@ -629,7 +629,6 @@ export interface CommonAstNode {
[x: string]: any
}
/// //////////////////////////////////////////////////////
/// ////////// YUL AST Nodes /////////////////////////////
/// //////////////////////////////////////////////////////
@ -674,7 +673,6 @@ export interface CommonYulAstNode {
[x: string]: any
}
/// ////////
// ERROR //
/// ////////

@ -2,7 +2,8 @@
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/prefer-namespace-keyword": "off"
"@typescript-eslint/prefer-namespace-keyword": "off",
"no-unused-vars": "off"
},
"ignorePatterns": ["!**/*"]
}

@ -1,12 +1,12 @@
import { EventEmitter } from "events";
import { Node, AstNode } from "./index";
import { EventEmitter } from 'events'
import { Node, AstNode } from './index'
export declare interface AstWalker {
new(): EventEmitter;
}
const isObject = function (obj: any): boolean {
return obj != null && obj.constructor.name === "Object"
return obj != null && obj.constructor.name === 'Object'
}
export function isAstNode (node: Record<string, unknown>): boolean {
@ -26,7 +26,6 @@ export function isYulAstNode(node: Record<string, unknown>): boolean {
)
}
/**
* Crawl the given AST through the function walk(ast, callback)
*/
@ -51,18 +50,18 @@ export class AstWalker extends EventEmitter {
// return that.
if (node) {
if ((node).name in callback) {
return callback[(node).name](node);
return callback[(node).name](node)
} else {
return callback["*"](node);
return callback['*'](node)
}
}
if (<AstNode>node) {
if ((<AstNode>node).nodeType in callback) {
/* istanbul ignore next */
return callback[(<AstNode>node).nodeType](node);
return callback[(<AstNode>node).nodeType](node)
} else {
/* istanbul ignore next */
return callback["*"](node);
return callback['*'](node)
}
}
}
@ -76,31 +75,30 @@ export class AstWalker extends EventEmitter {
nodes.forEach(x => {
if (Array.isArray(x)) objNodes.push(...x)
else objNodes.push(x)
});
})
// Filter duplicate nodes using id field
const normalizedNodes = []
objNodes.forEach((element) => {
const firstIndex = normalizedNodes.findIndex(e => e.id === element.id)
if(firstIndex == -1) normalizedNodes.push(element)
if (firstIndex === -1) normalizedNodes.push(element)
})
return normalizedNodes
}
getASTNodeChildren (ast: AstNode): AstNode[] {
let nodes = ast.nodes // for ContractDefinition
|| ast.body // for FunctionDefinition, ModifierDefinition, WhileStatement, DoWhileStatement, ForStatement
|| ast.statements // for Block, YulBlock
|| ast.members // for StructDefinition, EnumDefinition
|| ast.overrides // for OverrideSpecifier
|| ast.parameters // for ParameterList, EventDefinition
|| ast.declarations // for VariableDeclarationStatement
|| ast.expression // for Return, ExpressionStatement, FunctionCall, FunctionCallOptions, MemberAccess
|| ast.components // for TupleExpression
|| ast.subExpression // for UnaryOperation
|| ast.eventCall // for EmitStatement
|| []
let nodes = ast.nodes || // for ContractDefinition
ast.body || // for FunctionDefinition, ModifierDefinition, WhileStatement, DoWhileStatement, ForStatement
ast.statements || // for Block, YulBlock
ast.members || // for StructDefinition, EnumDefinition
ast.overrides || // for OverrideSpecifier
ast.parameters || // for ParameterList, EventDefinition
ast.declarations || // for VariableDeclarationStatement
ast.expression || // for Return, ExpressionStatement, FunctionCall, FunctionCallOptions, MemberAccess
ast.components || // for TupleExpression
ast.subExpression || // for UnaryOperation
ast.eventCall || // for EmitStatement
[]
// If 'nodes' is not an array, convert it into one, for example: ast.body
if (nodes && !Array.isArray(nodes)) {
@ -182,47 +180,48 @@ export class AstWalker extends EventEmitter {
const children: AstNode[] = this.getASTNodeChildren(ast)
if (callback) {
if (callback instanceof Function) {
callback = Object({ "*": callback });
callback = Object({ '*': callback })
}
if (!('*' in callback)) {
callback['*'] = function () {
return true
}
if (!("*" in callback)) {
callback["*"] = function() {
return true;
};
}
if (this.manageCallback(ast, callback) && children?.length) {
for (const k in children) {
const child = children[k];
this.walk(child, callback);
const child = children[k]
this.walk(child, callback)
}
}
} else {
if (children?.length) {
for (const k in children) {
const child = children[k];
this.emit("node", child);
this.walk(child);
const child = children[k]
this.emit('node', child)
this.walk(child)
}
}
}
}
}
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/explicit-module-boundary-types
walkFullInternal (ast: AstNode, callback: Function) {
if (isAstNode(ast) || isYulAstNode(ast)) {
// console.log(`XXX id ${ast.id}, nodeType: ${ast.nodeType}, src: ${ast.src}`);
callback(ast);
callback(ast)
for (const k of Object.keys(ast)) {
// Possible optimization:
// if (k in ['id', 'src', 'nodeType']) continue;
const astItem = ast[k];
const astItem = ast[k]
if (Array.isArray(astItem)) {
for (const child of astItem) {
if (child) {
this.walkFullInternal(child, callback);
this.walkFullInternal(child, callback)
}
}
} else {
this.walkFullInternal(astItem, callback);
this.walkFullInternal(astItem, callback)
}
}
}
@ -231,18 +230,18 @@ export class AstWalker extends EventEmitter {
// Normalizes parameter callback and calls walkFullInternal
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
walkFull (ast: AstNode, callback: any) {
if (isAstNode(ast) || isYulAstNode(ast)) return this.walkFullInternal(ast, callback);
if (isAstNode(ast) || isYulAstNode(ast)) return this.walkFullInternal(ast, callback)
}
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/explicit-module-boundary-types
walkAstList (sourcesList: Node, cb?: Function) {
if (cb) {
if (sourcesList.ast) {
this.walk(sourcesList.ast, cb);
this.walk(sourcesList.ast, cb)
}
} else {
if (sourcesList.ast) {
this.walk(sourcesList.ast);
this.walk(sourcesList.ast)
}
}
}

@ -1,6 +1,6 @@
import { isAstNode, isYulAstNode, AstWalker } from './astWalker';
import { AstNode, LineColPosition, LineColRange, Location } from "./types";
import { util } from "@remix-project/remix-lib";
import { isAstNode, isYulAstNode, AstWalker } from './astWalker'
import { AstNode, LineColPosition, LineColRange, Location } from './types'
import { util } from '@remix-project/remix-lib'
export declare interface SourceMappings {
// eslint-disable-next-line @typescript-eslint/no-misused-new
@ -13,11 +13,11 @@ export declare interface SourceMappings {
* @param offset The character offset to convert.
*/
export function lineColPositionFromOffset (offset: number, lineBreaks: Array<number>): LineColPosition {
let line: number = util.findLowerBound(offset, lineBreaks);
let line: number = util.findLowerBound(offset, lineBreaks)
if (lineBreaks[line] !== offset) {
line += 1;
line += 1
}
const beginColumn = line === 0 ? 0 : (lineBreaks[line - 1] + 1);
const beginColumn = line === 0 ? 0 : (lineBreaks[line - 1] + 1)
return <LineColPosition>{
line: line + 1,
character: (offset - beginColumn) + 1
@ -34,7 +34,7 @@ export function sourceLocationFromAstNode(astNode: AstNode): Location | null {
if (isAstNode(astNode) && isYulAstNode(astNode) && astNode.src) {
return sourceLocationFromSrc(astNode.src)
}
return null;
return null
}
/**
@ -59,20 +59,19 @@ export function sourceLocationFromSrc(src: string): Location {
* includng "src' information.
*/
export class SourceMappings {
readonly source: string;
readonly lineBreaks: Array<number>;
constructor (source: string) {
this.source = source;
this.source = source
// Create a list of line offsets which will be used to map between
// character offset and line/column positions.
const lineBreaks: Array<number> = [];
const lineBreaks: Array<number> = []
for (let pos = source.indexOf('\n'); pos >= 0; pos = source.indexOf('\n', pos + 1)) {
lineBreaks.push(pos)
}
this.lineBreaks = lineBreaks;
this.lineBreaks = lineBreaks
};
/**
@ -83,21 +82,21 @@ export class SourceMappings {
*/
nodesAtPosition (astNodeType: string | null, position: Location, ast: AstNode): Array<AstNode> {
const astWalker = new AstWalker()
const found: Array<AstNode> = [];
const found: Array<AstNode> = []
const callback = function (node: AstNode): boolean {
const nodeLocation = sourceLocationFromAstNode(node);
const nodeLocation = sourceLocationFromAstNode(node)
if (nodeLocation &&
nodeLocation.start == position.start &&
nodeLocation.length == position.length) {
nodeLocation.start === position.start &&
nodeLocation.length === position.length) {
if (!astNodeType || astNodeType === node.nodeType) {
found.push(node)
}
}
return true;
return true
}
astWalker.walkFull(ast, callback);
return found;
astWalker.walkFull(ast, callback)
return found
}
/**
@ -108,23 +107,23 @@ export class SourceMappings {
*/
findNodeAtSourceLocation (astNodeType: string | undefined, sourceLocation: Location, ast: AstNode | null): AstNode | null {
const astWalker = new AstWalker()
let found = null;
let found = null
/* FIXME: Looking at AST walker code,
I don't understand a need to return a boolean. */
const callback = function (node: AstNode) {
const nodeLocation = sourceLocationFromAstNode(node);
const nodeLocation = sourceLocationFromAstNode(node)
if (nodeLocation &&
nodeLocation.start == sourceLocation.start &&
nodeLocation.length == sourceLocation.length) {
if (astNodeType == undefined || astNodeType === node.nodeType) {
found = node;
nodeLocation.start === sourceLocation.start &&
nodeLocation.length === sourceLocation.length) {
if (astNodeType === undefined || astNodeType === node.nodeType) {
found = node
}
}
return true;
return true
}
astWalker.walkFull(ast, callback);
return found;
astWalker.walkFull(ast, callback)
return found
}
/**
@ -133,7 +132,7 @@ export class SourceMappings {
* @param src Solc "src" object containing attributes {source} and {length}.
*/
srcToLineColumnRange (src: string): LineColRange {
const sourceLocation = sourceLocationFromSrc(src);
const sourceLocation = sourceLocationFromSrc(src)
if (sourceLocation.start >= 0 && sourceLocation.length >= 0) {
return <LineColRange>{
start: lineColPositionFromOffset(sourceLocation.start, this.lineBreaks),
@ -146,5 +145,4 @@ export class SourceMappings {
}
}
}
}

@ -4,7 +4,7 @@
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-this-alias": "off",
"camelcase": "off"
"dot-notation": "off"
},
"env": {
"browser": true,

@ -12,7 +12,7 @@ export class Debugger {
compilationResult
debugger
breakPointManager
step_manager
step_manager // eslint-disable-line camelcase
vmDebuggerLogic
constructor (options) {

@ -17,11 +17,11 @@ export class RefType {
}
decodeFromStorage (input1? : any, input2? : any) {
throw new Error('This method is abstract');
throw new Error('This method is abstract')
}
decodeFromMemoryInternal (input1? : any, input2? : any, input3?: any) {
throw new Error('This method is abstract');
throw new Error('This method is abstract')
}
/**

@ -15,7 +15,7 @@ export class ValueType {
}
decodeValue (input? : any) {
throw new Error('This method is abstract');
throw new Error('This method is abstract')
}
/**

@ -1,5 +1,6 @@
'use strict'
import { util } from '@remix-project/remix-lib'
// eslint-disable-next-line camelcase
const { sha3_256 } = util
export class TraceCache {

@ -1,13 +1,9 @@
{
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-this-alias": "off",
"standard/no-callback-literal": "off",
"camelcase": "off",
"no-unused-vars": "off"
"no-unused-vars": "off",
"dot-notation": "off"
},
"env": {
"browser": true,

@ -163,6 +163,7 @@ export function buildCallPath (index, rootCall) {
* @param {String} value - value to sha3
* @return {Object} - return sha3ied value
*/
// eslint-disable-next-line camelcase
export function sha3_256 (value) {
if (typeof value === 'string' && value.indexOf('0x') !== 0) {
value = '0x' + value

@ -5,7 +5,8 @@
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-unused-vars": "off",
"camelcase": "off",
"dot-notation": "off"
"dot-notation": "off",
"no-unused-vars": "off"
},
"env": {
"browser": true,

@ -18,4 +18,3 @@ export function generateBlock (executionContext) {
executionContext.addBlock(block)
})
}

@ -1,5 +1,5 @@
const version = require('../../package.json').version
import Web3 from 'web3'
const version = require('../../package.json').version
export function methods () {
return {
@ -57,4 +57,3 @@ export function eth_compileLLL (payload, cb) {
export function eth_compileSerpent (payload, cb) {
cb(null, 'unsupported')
}

@ -1,6 +1,5 @@
import { Blocks } from './methods/blocks'
import { execution } from '@remix-project/remix-lib'
const { executionContext } = execution
import { info } from './utils/logs'
import merge from 'merge'
@ -12,6 +11,7 @@ import { methods as netMethods } from './methods/net'
import { Transactions } from './methods/transactions'
import { Debug } from './methods/debug'
import { generateBlock } from './genesis'
const { executionContext } = execution
export class Provider {
options: Record<string, unknown>
@ -85,7 +85,7 @@ export class Provider {
};
supportsSubscriptions () {
return true;
return true
};
on (type, cb) {

@ -1,13 +1,12 @@
import express from 'express'
import cors from 'cors'
import bodyParser from 'body-parser'
const app = express()
import expressWs from 'express-ws'
import { Provider } from './provider'
import { log } from './utils/logs'
const app = express()
class Server {
provider
rpcOnly

@ -1,9 +1,8 @@
{
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-unused-vars": "off"
"dot-notation": "off",
"no-unused-vars": "off"
},
"env": {
"browser": true,

@ -27,8 +27,7 @@ export default (sources: Source, opts: CompilerInputOptions): string => {
o.language = opts.language
}
if (opts.language === 'Yul' && o.settings.optimizer.enabled) {
if (!o.settings.optimizer.details)
o.settings.optimizer.details = {}
if (!o.settings.optimizer.details) { o.settings.optimizer.details = {} }
o.settings.optimizer.details.yul = true
}
return JSON.stringify(o)

@ -24,7 +24,7 @@ export default function (self) { // eslint-disable-line @typescript-eslint/expli
try {
const missingInputsCallback = (path) => {
missingInputs.push(path)
return { 'error': 'Deferred import' }
return { error: 'Deferred import' }
}
return compiler.compile(input, { import: missingInputsCallback })
} catch (exception) {

@ -4,11 +4,13 @@ import { update } from 'solc/abi'
import * as webworkify from 'webworkify-webpack'
import compilerInput from './compiler-input'
import EventManager from '../lib/eventManager'
import { default as txHelper } from './txHelper';
import { Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult,
import txHelper from './txHelper'
import {
Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult,
visitContractsCallbackParam, visitContractsCallbackInterface, CompilationError,
gatherImportsCallbackInterface,
isFunctionDescription } from './types'
isFunctionDescription
} from './types'
/*
trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration
@ -68,9 +70,8 @@ export class Compiler {
this.gatherImports(files, missingInputs, (error, input) => {
if (error) {
this.state.lastCompilationResult = null
this.event.trigger('compilationFinished', [false, {'error': { formattedMessage: error, severity: 'error' }}, files])
} else if(this.state.compileJSON && input)
this.state.compileJSON(input)
this.event.trigger('compilationFinished', [false, { error: { formattedMessage: error, severity: 'error' } }, files])
} else if (this.state.compileJSON && input) { this.state.compileJSON(input) }
})
}
@ -151,9 +152,8 @@ export class Compiler {
this.internalCompile(source.sources, missingInputs)
} else {
data = this.updateInterface(data)
if(source)
{
source.target = this.state.target;
if (source) {
source.target = this.state.target
this.state.lastCompilationResult = {
data: data,
source: source
@ -340,8 +340,7 @@ export class Compiler {
}
return
}
if(cb)
cb(null, { 'sources': files })
if (cb) { cb(null, { sources: files }) }
}
/**
@ -366,9 +365,9 @@ export class Compiler {
// yul compiler does not return any abi,
// we default to accept the fallback function (which expect raw data as argument).
contract.object.abi.push({
'payable': true,
'stateMutability': 'payable',
'type': 'fallback'
payable: true,
stateMutability: 'payable',
type: 'fallback'
})
}
if (data && data.contracts && this.state.currentVersion) {
@ -379,7 +378,7 @@ export class Compiler {
for (const item of data.contracts[contract.file][contract.name].abi) {
if (isFunctionDescription(item) && item.constant) {
item.payable = false
item.stateMutability = 'view';
item.stateMutability = 'view'
}
}
}
@ -457,4 +456,3 @@ export class Compiler {
return null
}
}

@ -9,7 +9,7 @@ export default {
* @param contracts 'contracts' object from last compilation result
*/
getContract: (contractName: string, contracts: CompilationResult["contracts"]) : Record<string, any> | null => {
getContract: (contractName: string, contracts: CompilationResult['contracts']) : Record<string, any> | null => {
for (const file in contracts) {
if (contracts[file][contractName]) {
return { object: contracts[file][contractName], file: file }
@ -24,7 +24,7 @@ export default {
* @param cb - callback
*/
visitContracts: (contracts: CompilationResult["contracts"], cb: visitContractsCallbackInterface) : void => {
visitContracts: (contracts: CompilationResult['contracts'], cb: visitContractsCallbackInterface) : void => {
for (const file in contracts) {
for (const name in contracts[file]) {
const param: visitContractsCallbackParam = {

@ -129,7 +129,6 @@ export interface CompilerInput {
}
}
export interface Source {
[fileName: string]:
{
@ -355,10 +354,10 @@ export interface CompilationResult {
export type ABIDescription = FunctionDescription | EventDescription
export const isFunctionDescription = (item: ABIDescription): item is FunctionDescription =>
(item as FunctionDescription).stateMutability !== undefined;
(item as FunctionDescription).stateMutability !== undefined
export const isEventDescription = (item: ABIDescription): item is EventDescription =>
(item as EventDescription).type === 'event';
(item as EventDescription).type === 'event'
export interface FunctionDescription {
/** Type of the method. default is 'function' */

@ -1,11 +1,8 @@
{
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/ban-ts-comment": "off"
"dot-notation": "off",
"no-unused-vars": "off"
},
"env": {
"browser": true,

@ -2,10 +2,10 @@ import fs from './fileSystem'
import async from 'async'
import path from 'path'
import Log from './logger'
const logger = new Log()
const log = logger.logger
import { Compiler as RemixCompiler } from '@remix-project/remix-solidity'
import { SrcIfc, CompilerConfiguration, CompilationErrors } from './types'
const logger = new Log()
const log = logger.logger
function regexIndexOf (inputString: string, regex: RegExp, startpos = 0) {
const indexOf = inputString.substring(startpos).search(regex)
@ -50,8 +50,7 @@ function processFile(filePath: string, sources: SrcIfc, isRoot = false) {
const isFileAlreadyInSources: boolean = Object.keys(sources).includes(filePath)
// Return if file is a remix test file or already processed
if(isRemixTestFile(filePath) || isFileAlreadyInSources)
return
if (isRemixTestFile(filePath) || isFileAlreadyInSources) { return }
let content: string = fs.readFileSync(filePath, { encoding: 'utf-8' })
const testFileImportRegEx = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm
@ -113,13 +112,11 @@ export function compileFileOrFiles(filename: string, isDirectory: boolean, opts:
})
if (testFileCount > 0) {
log.info(`${testFileCount} Solidity test file${testFileCount === 1 ? '' : 's'} found`)
}
else {
log.error(`No Solidity test file found. Make sure your test file ends with '_test.sol'`)
} else {
log.error('No Solidity test file found. Make sure your test file ends with \'_test.sol\'')
process.exit()
}
}
} catch (e) { // eslint-disable-line no-useless-catch
throw e
} finally {
@ -128,9 +125,9 @@ export function compileFileOrFiles(filename: string, isDirectory: boolean, opts:
compiler = new RemixCompiler()
if (compilerConfig) {
const { currentCompilerUrl, evmVersion, optimize, runs } = compilerConfig
evmVersion ? compiler.set('evmVersion', evmVersion) : null
optimize ? compiler.set('optimize', optimize) : null
runs ? compiler.set('runs', runs) : null
if (evmVersion) compiler.set('evmVersion', evmVersion)
if (optimize) compiler.set('optimize', optimize)
if (runs) compiler.set('runs', runs)
if (currentCompilerUrl) {
compiler.loadRemoteVersion(currentCompilerUrl)
compiler.event.register('compilerLoaded', this, function (version) {

@ -1,6 +1,6 @@
// Extend fs
const fs: any = require('fs')
import path from 'path'
const fs: any = require('fs')
// https://github.com/mikeal/node-utils/blob/master/file/lib/main.js
fs.walkSync = function (start: string, callback) {

@ -1,6 +1,6 @@
import colors from 'colors'
import winston, { Logger, LoggerOptions } from 'winston'
import timestamp from 'time-stamp';
import timestamp from 'time-stamp'
import supportsColor from 'color-support'
function hasFlag (flag: string) {
@ -42,7 +42,8 @@ class Log {
)
})
}
setVerbosity (v: LoggerOptions["level"]): void {
setVerbosity (v: LoggerOptions['level']): void {
this.logger.configure({
level: v,
transports: [new winston.transports.Console()],

@ -7,9 +7,9 @@ import fs from './fileSystem'
import { Provider } from '@remix-project/remix-simulator'
import { CompilerConfiguration } from './types'
import Log from './logger'
import colors from 'colors'
const logger = new Log()
const log = logger.logger
import colors from 'colors'
// parse verbosity
function mapVerbosity (v: number) {
@ -26,10 +26,10 @@ function mapVerbosity (v: number) {
function mapOptimize (v: string) {
const optimize = {
'true': true,
'false': false
true: true,
false: false
}
return optimize[v];
return optimize[v]
}
const version = require('../package.json').version
@ -52,7 +52,6 @@ commander
.option('-r, --runs <number>', 'set runs (e.g: 150, 250 etc)')
.option('-v, --verbose <level>', 'set verbosity level (0 to 5)', mapVerbosity)
.action(async (testsPath) => {
// Check if path exists
if (!fs.existsSync(testsPath)) {
log.error(testsPath + ' not found')
@ -77,7 +76,7 @@ commander
log.info('verbosity level set to ' + commander.verbose.blue)
}
let compilerConfig = {} as CompilerConfiguration
const compilerConfig = {} as CompilerConfiguration
if (commander.compiler) {
const compVersion = commander.compiler
const baseURL = 'https://binaries.soliditylang.org/wasm/'
@ -105,7 +104,7 @@ commander
if (commander.runs) {
if (!commander.optimize) {
log.error(`Optimization should be enabled for runs`)
log.error('Optimization should be enabled for runs')
process.exit()
}
compilerConfig.runs = commander.runs

@ -3,7 +3,7 @@ import fs from './fileSystem'
import { runTest } from './testRunner'
import { TestResultInterface, ResultsInterface, CompilerConfiguration, compilationInterface, ASTInterface, Options, AstNode } from './types'
import colors from 'colors'
import Web3 from 'web3';
import Web3 from 'web3'
import { compileFileOrFiles } from './compiler'
import { deployAll } from './deployer'
@ -59,8 +59,7 @@ export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3,
function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) {
// Extract AST of test contract file source
for (const filename in asts) {
if(filename.endsWith('_test.sol'))
sourceASTs[filename] = asts[filename].ast
if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast }
}
deployAll(compilationResult, web3, false, (err, contracts) => {
if (err) {
@ -101,7 +100,7 @@ export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3,
const errors: any[] = []
const _testCallback = function (err: Error | null | undefined, result: TestResultInterface) {
if(err) throw err;
if (err) throw err
if (result.type === 'contract') {
signale.name(result.value.white)
} else if (result.type === 'testPass') {

@ -1,14 +1,16 @@
import async, { ErrorCallback } from 'async'
require('colors')
import { compileContractSources } from './compiler'
import { deployAll } from './deployer'
import { runTest } from './testRunner'
import Web3 from 'web3';
import Web3 from 'web3'
import { Provider } from '@remix-project/remix-simulator'
import { FinalResult, SrcIfc, compilationInterface, ASTInterface, Options,
TestResultInterface, AstNode, CompilerConfiguration } from './types'
import {
FinalResult, SrcIfc, compilationInterface, ASTInterface, Options,
TestResultInterface, AstNode, CompilerConfiguration
} from './types'
require('colors')
const createWeb3Provider = async function () {
const web3 = new Web3()
@ -46,8 +48,7 @@ export async function runTestSources(contractSources: SrcIfc, compilerConfig: Co
},
function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) {
for (const filename in asts) {
if(filename.endsWith('_test.sol'))
sourceASTs[filename] = asts[filename].ast
if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast }
}
deployAll(compilationResult, web3, false, (err, contracts) => {
if (err) {
@ -59,10 +60,8 @@ export async function runTestSources(contractSources: SrcIfc, compilerConfig: Co
if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array
else next(null, compilationResult, contracts)
})
} else
next([{message: 'contract deployment failed: ' + err.message, severity: 'error'}]) // IDE expects errors in array
} else
next(null, compilationResult, contracts)
} else { next([{ message: 'contract deployment failed: ' + err.message, severity: 'error' }]) } // IDE expects errors in array
} else { next(null, compilationResult, contracts) }
})
},
function determineTestContractsToRun (compilationResult: compilationInterface, contracts: any, next) {
@ -85,7 +84,7 @@ export async function runTestSources(contractSources: SrcIfc, compilerConfig: Co
let totalFailing = 0
let totalTime = 0
const errors: any[] = []
// eslint-disable-next-line handle-callback-err
const _testCallback = function (err: Error | null | undefined, result: TestResultInterface) {
if (result.type === 'testFailure') {
errors.push(result)
@ -118,7 +117,7 @@ export async function runTestSources(contractSources: SrcIfc, compilerConfig: Co
totalPassing: 0,
totalFailing: 0,
totalTime: 0,
errors: [],
errors: []
}
finalResults.totalPassing = totalPassing || 0

@ -1,9 +1,11 @@
import async from 'async'
import * as changeCase from 'change-case'
import Web3 from 'web3';
import Web3 from 'web3'
import assertionEvents from './assertionEvents'
import { RunListInterface, TestCbInterface, TestResultInterface, ResultCbInterface,
CompiledContract, AstNode, Options, FunctionDescription, UserDocumentation } from './types'
import {
RunListInterface, TestCbInterface, TestResultInterface, ResultCbInterface,
CompiledContract, AstNode, Options, FunctionDescription, UserDocumentation
} from './types'
/**
* @dev Get function name using method signature
@ -107,11 +109,11 @@ function getAvailableFunctions (fileAST: AstNode, testContractName: string): str
if (fileAST.nodes && fileAST.nodes.length > 0) {
const contractAST: AstNode[] = fileAST.nodes.filter(node => isNodeName(node, testContractName) && isNodeType(node, 'ContractDefinition'))
if (contractAST.length > 0 && contractAST[0].nodes) {
const funcNodes: AstNode[] = contractAST[0].nodes.filter(node => ((node.kind === "function" && isNodeType(node, 'FunctionDefinition')) || isNodeType(node, 'FunctionDefinition')))
const funcNodes: AstNode[] = contractAST[0].nodes.filter(node => ((node.kind === 'function' && isNodeType(node, 'FunctionDefinition')) || isNodeType(node, 'FunctionDefinition')))
funcList = funcNodes.map(node => node.name)
}
}
return funcList;
return funcList
}
function getAssertMethodLocation (fileAST: AstNode, testContractName: string, functionName: string, assertMethod: string): string {
@ -123,12 +125,12 @@ function getAssertMethodLocation (fileAST: AstNode, testContractName: string, fu
// Assert.equal(foo.get(), 100, "initial value is not correct");
// return Assert.equal(foo.get(), 100, "initial value is not correct");
const expressions = funcNode.body.statements.filter(s =>
isNodeTypeIn(s, ['ExpressionStatement', 'Return'])
&& isNodeType(s.expression, 'FunctionCall'))
const assetExpression = expressions.find(e => e.expression.expression
&& isNodeType(e.expression.expression, 'MemberAccess')
&& e.expression.expression.memberName === assertMethod
&& isNodeName(e.expression.expression.expression, 'Assert')
isNodeTypeIn(s, ['ExpressionStatement', 'Return']) &&
isNodeType(s.expression, 'FunctionCall'))
const assetExpression = expressions.find(e => e.expression.expression &&
isNodeType(e.expression.expression, 'MemberAccess') &&
e.expression.expression.memberName === assertMethod &&
isNodeName(e.expression.expression.expression, 'Assert')
)
return assetExpression?.expression?.src
}
@ -213,8 +215,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
let failureNum = 0
let timePassed = 0
const isJSONInterfaceAvailable = testObject && testObject.options && testObject.options.jsonInterface
if(!isJSONInterfaceAvailable)
return resultsCallback(new Error('Contract interface not available'), { passingNum, failureNum, timePassed })
if (!isJSONInterfaceAvailable) { return resultsCallback(new Error('Contract interface not available'), { passingNum, failureNum, timePassed }) }
const runList: RunListInterface[] = createRunList(testObject.options.jsonInterface, fileAST, testName)
const web3 = new Web3()
const accts: TestResultInterface = {
@ -239,8 +240,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
}
let sendParams: Record<string, string> | null = null
if (sender) sendParams = { from: sender }
if(func.inputs && func.inputs.length > 0)
return resultsCallback(new Error(`Method '${func.name}' can not have parameters inside a test contract`), { passingNum, failureNum, timePassed })
if (func.inputs && func.inputs.length > 0) { return resultsCallback(new Error(`Method '${func.name}' can not have parameters inside a test contract`), { passingNum, failureNum, timePassed }) }
const method = testObject.methods[func.name].apply(testObject.methods[func.name], [])
const startTime = Date.now()
if (func.constant) {
@ -310,7 +310,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
returned: testEvent[3],
expected: testEvent[4],
location
};
}
testCallback(undefined, resp)
failureNum += 1
timePassed += time
@ -348,7 +348,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
time: time,
errMsg: err.message,
context: testName
};
}
testCallback(undefined, resp)
failureNum += 1
timePassed += time

@ -1,11 +1,6 @@
{
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
},
"rules": {},
"env": {
"browser": true,
"amd": true,

@ -1,3 +1,4 @@
// eslint-disable-next-line no-unused-vars
import axios, { AxiosResponse } from 'axios'
import { BzzNode as Bzz } from '@erebos/bzz-node'
@ -29,7 +30,7 @@ export class RemixURLResolver {
constructor (gistToken?: string, protocol = 'http:') {
this.previouslyHandled = {}
this.gistAccessToken = gistToken ? gistToken : ''
this.gistAccessToken = gistToken || ''
this.protocol = protocol
}
@ -39,15 +40,12 @@ export class RemixURLResolver {
* @param filePath path of the file in github
*/
async handleGithubCall (root: string, filePath: string): Promise<HandlerResponse> {
let param = '?'
param += this.gistAccessToken ? 'access_token=' + this.gistAccessToken : ''
const regex = filePath.match(/blob\/([^/]+)\/(.*)/)
let reference = 'master'
if (regex) {
// if we have /blob/master/+path we extract the branch name "master" and add it as a parameter to the github api
// the ref can be branch name, tag, commit id
reference = regex[1]
param += '&ref=' + reference
filePath = filePath.replace(`blob/${reference}/`, '')
}
// eslint-disable-next-line no-useless-catch
@ -93,7 +91,7 @@ export class RemixURLResolver {
async handleSwarm (url: string, cleanUrl: string): Promise<HandlerResponse> {
// eslint-disable-next-line no-useless-catch
try {
const bzz = new Bzz({url: this.protocol + '//swarm-gateways.net'});
const bzz = new Bzz({ url: this.protocol + '//swarm-gateways.net' })
const url = bzz.getDownloadURL(cleanUrl, { mode: 'raw' })
const response: AxiosResponse = await axios.get(url)
return { content: response.data, cleanUrl }
@ -184,7 +182,7 @@ export class RemixURLResolver {
const { content, cleanUrl } = await handler.handle(match)
imported = {
content,
cleanUrl : cleanUrl ? cleanUrl : filePath,
cleanUrl: cleanUrl || filePath,
type: handler.type
}
this.previouslyHandled[filePath] = imported

@ -41,7 +41,7 @@
"workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph",
"help": "nx help",
"lint:libs": "nx run-many --target=lint --projects=remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"publish:libs": "npm run build:libs & lerna publish --skip-git & npm run bumpVersion:libs",

@ -347,7 +347,7 @@
"linter": "eslint",
"config": "libs/remix-tests/.eslintrc",
"tsConfig": ["libs/remix-tests/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-tests/tests/**/*"]
"exclude": ["**/node_modules/**", "libs/remix-tests/tests/**/*", "**/dist/**"]
}
},
"test": {

Loading…
Cancel
Save