solidity-argus 0.2.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +93 -37
  3. package/package.json +34 -7
  4. package/skills/INVENTORY.md +88 -57
  5. package/skills/README.md +26 -23
  6. package/skills/case-studies/beanstalk-governance/SKILL.md +52 -0
  7. package/skills/case-studies/bzx-flash-loan/SKILL.md +53 -0
  8. package/skills/case-studies/cream-finance/SKILL.md +52 -0
  9. package/skills/case-studies/curve-reentrancy/SKILL.md +52 -0
  10. package/skills/case-studies/dao-hack/SKILL.md +51 -0
  11. package/skills/case-studies/euler-finance/SKILL.md +52 -0
  12. package/skills/case-studies/harvest-finance/SKILL.md +52 -0
  13. package/skills/case-studies/level-finance/SKILL.md +51 -0
  14. package/skills/case-studies/mango-markets/SKILL.md +53 -0
  15. package/skills/case-studies/nomad-bridge/SKILL.md +51 -0
  16. package/skills/case-studies/parity-multisig/SKILL.md +55 -0
  17. package/skills/case-studies/poly-network/SKILL.md +51 -0
  18. package/skills/case-studies/rari-fuse/SKILL.md +51 -0
  19. package/skills/case-studies/ronin-bridge/SKILL.md +52 -0
  20. package/skills/case-studies/wormhole-bridge/SKILL.md +51 -0
  21. package/skills/manifests/smartbugs.json +1 -3
  22. package/skills/manifests/sunweb3sec.json +1 -3
  23. package/skills/vulnerability-patterns/access-control/SKILL.md +14 -0
  24. package/skills/vulnerability-patterns/arbitrary-storage-location/SKILL.md +13 -1
  25. package/skills/vulnerability-patterns/assert-violation/SKILL.md +8 -1
  26. package/skills/vulnerability-patterns/asserting-contract-from-code-size/SKILL.md +12 -1
  27. package/skills/vulnerability-patterns/authorization-txorigin/SKILL.md +2 -1
  28. package/skills/vulnerability-patterns/cross-chain-bridge-vulnerabilities/SKILL.md +217 -0
  29. package/skills/vulnerability-patterns/default-visibility/SKILL.md +13 -1
  30. package/skills/vulnerability-patterns/delegatecall-untrusted-callee/SKILL.md +2 -1
  31. package/skills/vulnerability-patterns/dos-gas-limit/SKILL.md +8 -1
  32. package/skills/vulnerability-patterns/dos-revert/SKILL.md +1 -0
  33. package/skills/vulnerability-patterns/erc4626-exchange-rate-manipulation/SKILL.md +64 -0
  34. package/skills/vulnerability-patterns/fee-on-transfer-tokens/SKILL.md +93 -0
  35. package/skills/vulnerability-patterns/flash-loan-attacks/SKILL.md +1 -0
  36. package/skills/vulnerability-patterns/floating-pragma/SKILL.md +8 -1
  37. package/skills/vulnerability-patterns/front-running-attacks/SKILL.md +209 -0
  38. package/skills/vulnerability-patterns/gas-optimization-patterns/SKILL.md +203 -0
  39. package/skills/vulnerability-patterns/governance-attacks/SKILL.md +208 -0
  40. package/skills/vulnerability-patterns/hash-collision/SKILL.md +8 -1
  41. package/skills/vulnerability-patterns/inadherence-to-standards/SKILL.md +12 -1
  42. package/skills/vulnerability-patterns/incorrect-constructor/SKILL.md +8 -1
  43. package/skills/vulnerability-patterns/incorrect-inheritance-order/SKILL.md +8 -1
  44. package/skills/vulnerability-patterns/insufficient-gas-griefing/SKILL.md +12 -1
  45. package/skills/vulnerability-patterns/lack-of-precision/SKILL.md +7 -1
  46. package/skills/vulnerability-patterns/logic-errors/SKILL.md +10 -0
  47. package/skills/vulnerability-patterns/missing-parameter-bounds/SKILL.md +44 -0
  48. package/skills/vulnerability-patterns/missing-protection-signature-replay/SKILL.md +17 -1
  49. package/skills/vulnerability-patterns/msgvalue-loop/SKILL.md +12 -1
  50. package/skills/vulnerability-patterns/off-by-one/SKILL.md +7 -1
  51. package/skills/vulnerability-patterns/oracle-manipulation/SKILL.md +9 -0
  52. package/skills/vulnerability-patterns/outdated-compiler-version/SKILL.md +8 -1
  53. package/skills/vulnerability-patterns/overflow-underflow/SKILL.md +1 -0
  54. package/skills/vulnerability-patterns/proxy-vulnerabilities/SKILL.md +209 -0
  55. package/skills/vulnerability-patterns/reentrancy/SKILL.md +9 -0
  56. package/skills/vulnerability-patterns/shadowing-state-variables/SKILL.md +8 -1
  57. package/skills/vulnerability-patterns/share-accounting-desynchronization/SKILL.md +44 -0
  58. package/skills/vulnerability-patterns/signature-malleability/SKILL.md +2 -1
  59. package/skills/vulnerability-patterns/stateful-parameter-update-drift/SKILL.md +44 -0
  60. package/skills/vulnerability-patterns/unbounded-return-data/SKILL.md +12 -1
  61. package/skills/vulnerability-patterns/unchecked-return-values/SKILL.md +2 -1
  62. package/skills/vulnerability-patterns/unencrypted-private-data-on-chain/SKILL.md +8 -1
  63. package/skills/vulnerability-patterns/unexpected-ecrecover-null-address/SKILL.md +8 -1
  64. package/skills/vulnerability-patterns/uninitialized-storage-pointer/SKILL.md +8 -1
  65. package/skills/vulnerability-patterns/unsafe-erc20-transfers/SKILL.md +132 -0
  66. package/skills/vulnerability-patterns/unsafe-low-level-call/SKILL.md +12 -1
  67. package/skills/vulnerability-patterns/unsecure-signatures/SKILL.md +12 -1
  68. package/skills/vulnerability-patterns/unsupported-opcodes/SKILL.md +11 -1
  69. package/skills/vulnerability-patterns/unused-variables/SKILL.md +8 -1
  70. package/skills/vulnerability-patterns/use-of-deprecated-functions/SKILL.md +8 -1
  71. package/skills/vulnerability-patterns/weak-sources-randomness/SKILL.md +8 -1
  72. package/skills/vulnerability-patterns/weird-tokens/SKILL.md +10 -0
  73. package/skills/vulnerability-patterns/zero-address-misconfiguration/SKILL.md +48 -0
  74. package/src/agents/argus-prompt.ts +34 -7
  75. package/src/agents/pythia-prompt.ts +13 -4
  76. package/src/agents/scribe-prompt.ts +20 -2
  77. package/src/agents/sentinel-prompt.ts +45 -5
  78. package/src/cli/cli-program.ts +29 -26
  79. package/src/cli/commands/check-skills.ts +135 -0
  80. package/src/cli/commands/doctor.ts +48 -26
  81. package/src/cli/commands/init.ts +5 -3
  82. package/src/cli/commands/install.ts +7 -5
  83. package/src/cli/commands/lint-skills.ts +16 -12
  84. package/src/cli/index.ts +5 -5
  85. package/src/cli/types.ts +3 -3
  86. package/src/config/index.ts +1 -1
  87. package/src/config/loader.ts +4 -6
  88. package/src/config/schema.ts +6 -5
  89. package/src/config/types.ts +2 -2
  90. package/src/constants/defaults.ts +2 -0
  91. package/src/create-hooks.ts +145 -34
  92. package/src/create-managers.ts +10 -8
  93. package/src/create-tools.ts +13 -9
  94. package/src/features/background-agent/background-manager.ts +93 -87
  95. package/src/features/background-agent/index.ts +1 -1
  96. package/src/features/context-monitor/context-monitor.ts +3 -3
  97. package/src/features/context-monitor/index.ts +2 -2
  98. package/src/features/error-recovery/session-recovery.ts +2 -4
  99. package/src/features/error-recovery/tool-error-recovery.ts +12 -7
  100. package/src/features/index.ts +5 -5
  101. package/src/features/persistent-state/audit-state-manager.ts +143 -60
  102. package/src/features/persistent-state/global-run-index.ts +38 -0
  103. package/src/features/persistent-state/index.ts +1 -1
  104. package/src/features/persistent-state/run-journal.ts +86 -0
  105. package/src/hooks/config-handler.ts +28 -11
  106. package/src/hooks/context-budget.ts +2 -5
  107. package/src/hooks/event-hook.ts +47 -23
  108. package/src/hooks/hook-system.ts +4 -4
  109. package/src/hooks/index.ts +5 -5
  110. package/src/hooks/knowledge-sync-hook.ts +18 -21
  111. package/src/hooks/recon-context-builder.ts +2 -2
  112. package/src/hooks/safe-create-hook.ts +6 -7
  113. package/src/hooks/system-prompt-hook.ts +18 -1
  114. package/src/hooks/tool-tracking-hook.ts +110 -51
  115. package/src/hooks/types.ts +2 -1
  116. package/src/index.ts +24 -37
  117. package/src/knowledge/retry.ts +22 -22
  118. package/src/knowledge/scvd-client.ts +88 -95
  119. package/src/knowledge/scvd-errors.ts +35 -35
  120. package/src/knowledge/scvd-index.ts +78 -80
  121. package/src/knowledge/scvd-sync.ts +106 -101
  122. package/src/managers/index.ts +1 -1
  123. package/src/managers/types.ts +19 -14
  124. package/src/plugin-interface.ts +7 -9
  125. package/src/shared/binary-utils.ts +44 -35
  126. package/src/shared/deep-merge.ts +55 -36
  127. package/src/shared/file-utils.ts +21 -19
  128. package/src/shared/index.ts +11 -5
  129. package/src/shared/jsonc-parser.ts +123 -28
  130. package/src/shared/logger.ts +16 -3
  131. package/src/shared/project-utils.ts +30 -0
  132. package/src/skills/analysis/cluster.ts +414 -0
  133. package/src/skills/analysis/gates.ts +227 -0
  134. package/src/skills/analysis/index.ts +33 -0
  135. package/src/skills/analysis/normalize.ts +217 -0
  136. package/src/skills/analysis/similarity.ts +224 -0
  137. package/src/skills/argus-skill-resolver.ts +17 -6
  138. package/src/skills/skill-schema.ts +11 -10
  139. package/src/solodit-lifecycle.ts +203 -0
  140. package/src/state/audit-state.ts +8 -8
  141. package/src/state/finding-store.ts +68 -55
  142. package/src/state/types.ts +88 -67
  143. package/src/tools/argus-skill-load-tool.ts +12 -7
  144. package/src/tools/contract-analyzer-tool.ts +142 -77
  145. package/src/tools/forge-coverage-tool.ts +226 -0
  146. package/src/tools/forge-fuzz-tool.ts +127 -127
  147. package/src/tools/forge-test-tool.ts +201 -158
  148. package/src/tools/gas-analysis-tool.ts +264 -0
  149. package/src/tools/pattern-checker-tool.ts +203 -191
  150. package/src/tools/pattern-loader.ts +5 -111
  151. package/src/tools/pattern-schema.ts +3 -0
  152. package/src/tools/proxy-detection-tool.ts +224 -0
  153. package/src/tools/report-generator-tool.ts +305 -206
  154. package/src/tools/slither-tool.ts +266 -218
  155. package/src/tools/solodit-search-tool.ts +235 -119
  156. package/src/tools/sync-knowledge-tool.ts +7 -11
  157. package/src/utils/audit-artifact-detector.ts +28 -29
  158. package/src/utils/dependency-scanner.ts +37 -37
  159. package/src/utils/project-detector.ts +111 -124
  160. package/src/utils/solidity-parser.ts +175 -75
  161. package/skills/patterns/access-control.yaml +0 -31
  162. package/skills/patterns/erc4626.yaml +0 -29
  163. package/skills/patterns/flash-loan.yaml +0 -20
  164. package/skills/patterns/oracle.yaml +0 -30
  165. package/skills/patterns/proxy.yaml +0 -30
  166. package/skills/patterns/reentrancy.yaml +0 -30
  167. package/skills/patterns/signature.yaml +0 -31
  168. package/src/hooks/event-hook-v2.ts +0 -99
  169. package/src/state/plugin-state.ts +0 -14
@@ -1,45 +1,46 @@
1
1
  export interface DependencyRisk {
2
- package: string;
3
- version: string;
4
- risk: "high" | "medium" | "low";
5
- category: string;
6
- recommendation: string;
2
+ package: string
3
+ version: string
4
+ risk: "high" | "medium" | "low"
5
+ category: string
6
+ recommendation: string
7
7
  }
8
8
 
9
9
  interface DependencyInput {
10
- dependencies?: Record<string, string>;
11
- devDependencies?: Record<string, string>;
10
+ dependencies?: Record<string, string>
11
+ devDependencies?: Record<string, string>
12
12
  }
13
13
 
14
14
  function parseVersion(raw: string): [number, number, number] {
15
- const cleaned = raw.replace(/^[^0-9]*/, "");
16
- const parts = cleaned.split(".");
15
+ const cleaned = raw.replace(/^[^0-9]*/, "")
16
+ if (!cleaned) {
17
+ return [0, 0, 0]
18
+ }
19
+ const parts = cleaned.split(".")
20
+ const major = parseInt(parts[0] ?? "0", 10)
21
+ const minor = parseInt(parts[1] ?? "0", 10)
22
+ const patch = parseInt(parts[2] ?? "0", 10)
17
23
  return [
18
- parseInt(parts[0] ?? "0", 10),
19
- parseInt(parts[1] ?? "0", 10),
20
- parseInt(parts[2] ?? "0", 10),
21
- ];
24
+ Number.isNaN(major) ? 0 : major,
25
+ Number.isNaN(minor) ? 0 : minor,
26
+ Number.isNaN(patch) ? 0 : patch,
27
+ ]
22
28
  }
23
29
 
24
- function versionLt(
25
- raw: string,
26
- major: number,
27
- minor: number,
28
- patch = 0
29
- ): boolean {
30
- const [a, b, c] = parseVersion(raw);
31
- if (a !== major) return a < major;
32
- if (b !== minor) return b < minor;
33
- return c < patch;
30
+ function versionLt(raw: string, major: number, minor: number, patch = 0): boolean {
31
+ const [a, b, c] = parseVersion(raw)
32
+ if (a !== major) return a < major
33
+ if (b !== minor) return b < minor
34
+ return c < patch
34
35
  }
35
36
 
36
37
  export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
37
- const risks: DependencyRisk[] = [];
38
- const deps = input.dependencies ?? {};
39
- const devDeps = input.devDependencies ?? {};
40
- const allDeps = { ...deps, ...devDeps };
38
+ const risks: DependencyRisk[] = []
39
+ const deps = input.dependencies ?? {}
40
+ const devDeps = input.devDependencies ?? {}
41
+ const allDeps = { ...deps, ...devDeps }
41
42
 
42
- const ozVersion = deps["@openzeppelin/contracts"];
43
+ const ozVersion = deps["@openzeppelin/contracts"]
43
44
  if (ozVersion) {
44
45
  if (versionLt(ozVersion, 4, 9)) {
45
46
  risks.push({
@@ -49,7 +50,7 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
49
50
  category: "known-vulnerability",
50
51
  recommendation:
51
52
  "Upgrade to @openzeppelin/contracts >= 4.9.0 — known vulnerabilities in OZ < 4.9",
52
- });
53
+ })
53
54
  } else if (versionLt(ozVersion, 5, 0)) {
54
55
  risks.push({
55
56
  package: "@openzeppelin/contracts",
@@ -58,14 +59,13 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
58
59
  category: "upgrade-available",
59
60
  recommendation:
60
61
  "Consider upgrading to OZ v5 for latest patterns and Solidity 0.8.20+ support",
61
- });
62
+ })
62
63
  }
63
64
  }
64
65
 
65
- const ozUpgradeableVersion = deps["@openzeppelin/contracts-upgradeable"];
66
+ const ozUpgradeableVersion = deps["@openzeppelin/contracts-upgradeable"]
66
67
  if (ozUpgradeableVersion) {
67
- const hasUpgradeTooling =
68
- "@openzeppelin/hardhat-upgrades" in allDeps;
68
+ const hasUpgradeTooling = "@openzeppelin/hardhat-upgrades" in allDeps
69
69
  if (!hasUpgradeTooling) {
70
70
  risks.push({
71
71
  package: "@openzeppelin/contracts-upgradeable",
@@ -74,11 +74,11 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
74
74
  category: "missing-tooling",
75
75
  recommendation:
76
76
  "Add @openzeppelin/hardhat-upgrades to devDependencies for safe upgrade workflows",
77
- });
77
+ })
78
78
  }
79
79
  }
80
80
 
81
- const solmateVersion = deps["solmate"];
81
+ const solmateVersion = deps.solmate
82
82
  if (solmateVersion && versionLt(solmateVersion, 6, 0)) {
83
83
  risks.push({
84
84
  package: "solmate",
@@ -86,8 +86,8 @@ export function scanDependencyRisks(input: DependencyInput): DependencyRisk[] {
86
86
  risk: "medium",
87
87
  category: "outdated",
88
88
  recommendation: "Upgrade solmate to >= 6.0.0 for latest fixes",
89
- });
89
+ })
90
90
  }
91
91
 
92
- return risks;
92
+ return risks
93
93
  }
@@ -1,25 +1,25 @@
1
- import { existsSync } from "fs";
2
- import { join, resolve } from "path";
3
- import { scanDependencyRisks, type DependencyRisk } from "./dependency-scanner";
1
+ import { existsSync } from "node:fs"
2
+ import { join, resolve } from "node:path"
3
+ import { type DependencyRisk, scanDependencyRisks } from "./dependency-scanner"
4
4
 
5
5
  export interface ProjectConfig {
6
- type: "foundry" | "hardhat" | "mixed" | "unknown";
7
- srcDir: string;
8
- testDir: string;
9
- solcVersion?: string;
10
- remappings: string[];
11
- viaIr: boolean;
12
- rootDir: string;
13
- optimizer?: { enabled: boolean; runs?: number };
14
- evmVersion?: string;
15
- profiles?: string[];
16
- hasHardhat: boolean;
17
- hasFoundry: boolean;
18
- dependencies?: Record<string, string>;
19
- devDependencies?: Record<string, string>;
20
- isUpgradeable: boolean;
21
- outDir?: string;
22
- dependencyRisks: DependencyRisk[];
6
+ type: "foundry" | "hardhat" | "mixed" | "unknown"
7
+ srcDir: string
8
+ testDir: string
9
+ solcVersion?: string
10
+ remappings: string[]
11
+ viaIr: boolean
12
+ rootDir: string
13
+ optimizer?: { enabled: boolean; runs?: number }
14
+ evmVersion?: string
15
+ profiles?: string[]
16
+ hasHardhat: boolean
17
+ hasFoundry: boolean
18
+ dependencies?: Record<string, string>
19
+ devDependencies?: Record<string, string>
20
+ isUpgradeable: boolean
21
+ outDir?: string
22
+ dependencyRisks: DependencyRisk[]
23
23
  }
24
24
 
25
25
  /**
@@ -28,63 +28,63 @@ export interface ProjectConfig {
28
28
  * @returns ProjectConfig with detected framework type and settings
29
29
  */
30
30
  export async function detectProject(dir: string): Promise<ProjectConfig> {
31
- const rootDir = resolve(dir);
32
- const foundryTomlPath = join(rootDir, "foundry.toml");
33
- const hardhatConfigTsPath = join(rootDir, "hardhat.config.ts");
34
- const hardhatConfigJsPath = join(rootDir, "hardhat.config.js");
31
+ const rootDir = resolve(dir)
32
+ const foundryTomlPath = join(rootDir, "foundry.toml")
33
+ const hardhatConfigTsPath = join(rootDir, "hardhat.config.ts")
34
+ const hardhatConfigJsPath = join(rootDir, "hardhat.config.js")
35
35
 
36
- const hasFoundry = existsSync(foundryTomlPath);
37
- const hasHardhatTs = existsSync(hardhatConfigTsPath);
38
- const hasHardhatJs = existsSync(hardhatConfigJsPath);
39
- const hasHardhat = hasHardhatTs || hasHardhatJs;
36
+ const hasFoundry = existsSync(foundryTomlPath)
37
+ const hasHardhatTs = existsSync(hardhatConfigTsPath)
38
+ const hasHardhatJs = existsSync(hardhatConfigJsPath)
39
+ const hasHardhat = hasHardhatTs || hasHardhatJs
40
40
 
41
41
  // Determine project type
42
- let type: "foundry" | "hardhat" | "mixed" | "unknown";
42
+ let type: "foundry" | "hardhat" | "mixed" | "unknown"
43
43
  if (hasFoundry && hasHardhat) {
44
- type = "mixed";
44
+ type = "mixed"
45
45
  } else if (hasFoundry) {
46
- type = "foundry";
46
+ type = "foundry"
47
47
  } else if (hasHardhat) {
48
- type = "hardhat";
48
+ type = "hardhat"
49
49
  } else {
50
- type = "unknown";
50
+ type = "unknown"
51
51
  }
52
52
 
53
- let srcDir = "src";
54
- let testDir = "test";
55
- let solcVersion: string | undefined;
56
- let remappings: string[] = [];
57
- let viaIr = false;
58
- let optimizer: { enabled: boolean; runs?: number } | undefined;
59
- let evmVersion: string | undefined;
60
- let profiles: string[] | undefined;
61
- let outDir: string | undefined;
53
+ let srcDir = "src"
54
+ let testDir = "test"
55
+ let solcVersion: string | undefined
56
+ let remappings: string[] = []
57
+ let viaIr = false
58
+ let optimizer: { enabled: boolean; runs?: number } | undefined
59
+ let evmVersion: string | undefined
60
+ let profiles: string[] | undefined
61
+ let outDir: string | undefined
62
62
 
63
63
  if (hasFoundry) {
64
- const foundryConfig = await parseFoundryToml(foundryTomlPath);
65
- srcDir = foundryConfig.srcDir || srcDir;
66
- testDir = foundryConfig.testDir || testDir;
67
- solcVersion = foundryConfig.solcVersion;
68
- remappings = foundryConfig.remappings;
69
- viaIr = foundryConfig.viaIr;
70
- optimizer = foundryConfig.optimizer;
71
- evmVersion = foundryConfig.evmVersion;
72
- profiles = foundryConfig.profiles;
73
- outDir = foundryConfig.outDir;
74
- }
75
-
76
- const remappingsFromTxt = parseRemappingsTxt(rootDir);
64
+ const foundryConfig = await parseFoundryToml(foundryTomlPath)
65
+ srcDir = foundryConfig.srcDir || srcDir
66
+ testDir = foundryConfig.testDir || testDir
67
+ solcVersion = foundryConfig.solcVersion
68
+ remappings = foundryConfig.remappings
69
+ viaIr = foundryConfig.viaIr
70
+ optimizer = foundryConfig.optimizer
71
+ evmVersion = foundryConfig.evmVersion
72
+ profiles = foundryConfig.profiles
73
+ outDir = foundryConfig.outDir
74
+ }
75
+
76
+ const remappingsFromTxt = parseRemappingsTxt(rootDir)
77
77
  if (remappingsFromTxt.length > 0 && remappings.length === 0) {
78
- remappings = remappingsFromTxt;
78
+ remappings = remappingsFromTxt
79
79
  }
80
80
 
81
81
  if (hasHardhat && !hasFoundry) {
82
- srcDir = "contracts";
82
+ srcDir = "contracts"
83
83
  }
84
84
 
85
- const isUpgradeable = existsSync(join(rootDir, ".openzeppelin"));
85
+ const isUpgradeable = existsSync(join(rootDir, ".openzeppelin"))
86
86
 
87
- const { dependencies, devDependencies } = await parsePackageJson(rootDir);
87
+ const { dependencies, devDependencies } = await parsePackageJson(rootDir)
88
88
 
89
89
  return {
90
90
  type,
@@ -104,26 +104,26 @@ export async function detectProject(dir: string): Promise<ProjectConfig> {
104
104
  isUpgradeable,
105
105
  outDir,
106
106
  dependencyRisks: scanDependencyRisks({ dependencies, devDependencies }),
107
- };
107
+ }
108
108
  }
109
109
 
110
110
  /**
111
111
  * Parses foundry.toml file using regex-based parsing
112
112
  */
113
113
  interface FoundryTomlResult {
114
- srcDir?: string;
115
- testDir?: string;
116
- solcVersion?: string;
117
- remappings: string[];
118
- viaIr: boolean;
119
- optimizer?: { enabled: boolean; runs?: number };
120
- evmVersion?: string;
121
- profiles?: string[];
122
- outDir?: string;
114
+ srcDir?: string
115
+ testDir?: string
116
+ solcVersion?: string
117
+ remappings: string[]
118
+ viaIr: boolean
119
+ optimizer?: { enabled: boolean; runs?: number }
120
+ evmVersion?: string
121
+ profiles?: string[]
122
+ outDir?: string
123
123
  }
124
124
 
125
125
  async function parseFoundryToml(filePath: string): Promise<FoundryTomlResult> {
126
- const content = await Bun.file(filePath).text();
126
+ const content = await Bun.file(filePath).text()
127
127
 
128
128
  const result: FoundryTomlResult = {
129
129
  srcDir: undefined,
@@ -131,117 +131,104 @@ async function parseFoundryToml(filePath: string): Promise<FoundryTomlResult> {
131
131
  solcVersion: undefined,
132
132
  remappings: [],
133
133
  viaIr: false,
134
- };
134
+ }
135
135
 
136
- const profileNames = Array.from(
137
- content.matchAll(/\[profile\.(\w+)\]/g),
138
- (m) => m[1]!
139
- );
136
+ const profileNames = Array.from(content.matchAll(/\[profile\.(\w+)\]/g), (m) => m[1]).filter(
137
+ (name): name is string => Boolean(name),
138
+ )
140
139
  if (profileNames.length > 0) {
141
- result.profiles = profileNames;
140
+ result.profiles = profileNames
142
141
  }
143
142
 
144
- const profileDefaultMatch = content.match(
145
- /\[profile\.default\]([\s\S]*?)(?:\n\[|$)/
146
- );
143
+ const profileDefaultMatch = content.match(/\[profile\.default\]([\s\S]*?)(?:\n\[|$)/)
147
144
  if (!profileDefaultMatch || !profileDefaultMatch[1]) {
148
- return result;
145
+ return result
149
146
  }
150
147
 
151
- const profileSection = profileDefaultMatch[1];
148
+ const profileSection = profileDefaultMatch[1]
152
149
 
153
- const srcMatch = profileSection.match(/^\s*src\s*=\s*["']([^"']+)["']/m);
150
+ const srcMatch = profileSection.match(/^\s*src\s*=\s*["']([^"']+)["']/m)
154
151
  if (srcMatch?.[1]) {
155
- result.srcDir = srcMatch[1];
152
+ result.srcDir = srcMatch[1]
156
153
  }
157
154
 
158
- const testMatch = profileSection.match(/^\s*test\s*=\s*["']([^"']+)["']/m);
155
+ const testMatch = profileSection.match(/^\s*test\s*=\s*["']([^"']+)["']/m)
159
156
  if (testMatch?.[1]) {
160
- result.testDir = testMatch[1];
157
+ result.testDir = testMatch[1]
161
158
  }
162
159
 
163
- const solcMatch = profileSection.match(/^\s*solc\s*=\s*["']([^"']+)["']/m);
160
+ const solcMatch = profileSection.match(/^\s*solc\s*=\s*["']([^"']+)["']/m)
164
161
  if (solcMatch?.[1]) {
165
- result.solcVersion = solcMatch[1];
162
+ result.solcVersion = solcMatch[1]
166
163
  }
167
164
 
168
- const viaIrMatch = profileSection.match(/^\s*via[_-]ir\s*=\s*(true|false)/m);
165
+ const viaIrMatch = profileSection.match(/^\s*via[_-]ir\s*=\s*(true|false)/m)
169
166
  if (viaIrMatch?.[1] === "true") {
170
- result.viaIr = true;
167
+ result.viaIr = true
171
168
  }
172
169
 
173
- const optimizerMatch = profileSection.match(
174
- /^\s*optimizer\s*=\s*(true|false)/m
175
- );
170
+ const optimizerMatch = profileSection.match(/^\s*optimizer\s*=\s*(true|false)/m)
176
171
  if (optimizerMatch?.[1]) {
177
- const enabled = optimizerMatch[1] === "true";
178
- const runsMatch = profileSection.match(
179
- /^\s*optimizer_runs\s*=\s*(\d+)/m
180
- );
172
+ const enabled = optimizerMatch[1] === "true"
173
+ const runsMatch = profileSection.match(/^\s*optimizer_runs\s*=\s*(\d+)/m)
181
174
  result.optimizer = {
182
175
  enabled,
183
176
  runs: runsMatch?.[1] ? parseInt(runsMatch[1], 10) : undefined,
184
- };
177
+ }
185
178
  }
186
179
 
187
- const evmMatch = profileSection.match(
188
- /^\s*evm_version\s*=\s*["']([^"']+)["']/m
189
- );
180
+ const evmMatch = profileSection.match(/^\s*evm_version\s*=\s*["']([^"']+)["']/m)
190
181
  if (evmMatch?.[1]) {
191
- result.evmVersion = evmMatch[1];
182
+ result.evmVersion = evmMatch[1]
192
183
  }
193
184
 
194
- const outMatch = profileSection.match(/^\s*out\s*=\s*["']([^"']+)["']/m);
185
+ const outMatch = profileSection.match(/^\s*out\s*=\s*["']([^"']+)["']/m)
195
186
  if (outMatch?.[1]) {
196
- result.outDir = outMatch[1];
187
+ result.outDir = outMatch[1]
197
188
  }
198
189
 
199
- const remappingsMatch = profileSection.match(
200
- /remappings\s*=\s*\[([\s\S]*?)\]/
201
- );
190
+ const remappingsMatch = profileSection.match(/remappings\s*=\s*\[([\s\S]*?)\]/)
202
191
  if (remappingsMatch?.[1]) {
203
- const remappingMatches = remappingsMatch[1].match(/["']([^"']+)["']/g);
192
+ const remappingMatches = remappingsMatch[1].match(/["']([^"']+)["']/g)
204
193
  if (remappingMatches) {
205
- result.remappings = remappingMatches.map((m) => m.slice(1, -1));
194
+ result.remappings = remappingMatches.map((m) => m.slice(1, -1))
206
195
  }
207
196
  }
208
197
 
209
- return result;
198
+ return result
210
199
  }
211
200
 
212
- async function parsePackageJson(
213
- rootDir: string
214
- ): Promise<{
215
- dependencies?: Record<string, string>;
216
- devDependencies?: Record<string, string>;
201
+ async function parsePackageJson(rootDir: string): Promise<{
202
+ dependencies?: Record<string, string>
203
+ devDependencies?: Record<string, string>
217
204
  }> {
218
- const pkgPath = join(rootDir, "package.json");
205
+ const pkgPath = join(rootDir, "package.json")
219
206
  if (!existsSync(pkgPath)) {
220
- return {};
207
+ return {}
221
208
  }
222
209
  try {
223
- const content = JSON.parse(await Bun.file(pkgPath).text());
210
+ const content = JSON.parse(await Bun.file(pkgPath).text())
224
211
  return {
225
212
  dependencies: content.dependencies,
226
213
  devDependencies: content.devDependencies,
227
- };
214
+ }
228
215
  } catch {
229
- return {};
216
+ return {}
230
217
  }
231
218
  }
232
219
 
233
220
  function parseRemappingsTxt(rootDir: string): string[] {
234
- const remappingsPath = join(rootDir, "remappings.txt");
221
+ const remappingsPath = join(rootDir, "remappings.txt")
235
222
  if (!existsSync(remappingsPath)) {
236
- return [];
223
+ return []
237
224
  }
238
225
  try {
239
- const content = require("fs").readFileSync(remappingsPath, "utf-8");
226
+ const content = require("node:fs").readFileSync(remappingsPath, "utf-8")
240
227
  return content
241
228
  .split("\n")
242
229
  .map((line: string) => line.trim())
243
- .filter((line: string) => line.length > 0);
230
+ .filter((line: string) => line.length > 0)
244
231
  } catch {
245
- return [];
232
+ return []
246
233
  }
247
234
  }