kirograph 0.16.1 → 0.19.0

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 (365) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +103 -1605
  3. package/dist/architecture/layers/dart.js +112 -0
  4. package/dist/architecture/layers/dart.js.map +7 -0
  5. package/dist/architecture/layers/index.js +3 -1
  6. package/dist/architecture/layers/index.js.map +2 -2
  7. package/dist/bin/banner.js +74 -6
  8. package/dist/bin/banner.js.map +2 -2
  9. package/dist/bin/commands/affected.js +40 -5
  10. package/dist/bin/commands/affected.js.map +2 -2
  11. package/dist/bin/commands/attack-surface.js +157 -0
  12. package/dist/bin/commands/attack-surface.js.map +7 -0
  13. package/dist/bin/commands/benchmark.js +206 -0
  14. package/dist/bin/commands/benchmark.js.map +7 -0
  15. package/dist/bin/commands/budget.js +70 -0
  16. package/dist/bin/commands/budget.js.map +7 -0
  17. package/dist/bin/commands/communities.js +77 -0
  18. package/dist/bin/commands/communities.js.map +7 -0
  19. package/dist/bin/commands/data.js +665 -0
  20. package/dist/bin/commands/data.js.map +7 -0
  21. package/dist/bin/commands/dep-confusion.js +119 -0
  22. package/dist/bin/commands/dep-confusion.js.map +7 -0
  23. package/dist/bin/commands/export.js +304 -10
  24. package/dist/bin/commands/export.js.map +2 -2
  25. package/dist/bin/commands/flows.js +97 -0
  26. package/dist/bin/commands/flows.js.map +7 -0
  27. package/dist/bin/commands/help.js +386 -100
  28. package/dist/bin/commands/help.js.map +2 -2
  29. package/dist/bin/commands/install.js +90 -8
  30. package/dist/bin/commands/install.js.map +2 -2
  31. package/dist/bin/commands/licenses.js +201 -0
  32. package/dist/bin/commands/licenses.js.map +7 -0
  33. package/dist/bin/commands/reachability.js +160 -0
  34. package/dist/bin/commands/reachability.js.map +7 -0
  35. package/dist/bin/commands/read.js +100 -0
  36. package/dist/bin/commands/read.js.map +7 -0
  37. package/dist/bin/commands/refactor.js +116 -0
  38. package/dist/bin/commands/refactor.js.map +7 -0
  39. package/dist/bin/commands/remediation.js +133 -0
  40. package/dist/bin/commands/remediation.js.map +7 -0
  41. package/dist/bin/commands/sbom.js +76 -0
  42. package/dist/bin/commands/sbom.js.map +7 -0
  43. package/dist/bin/commands/security-ci-report.js +267 -0
  44. package/dist/bin/commands/security-ci-report.js.map +7 -0
  45. package/dist/bin/commands/security-export.js +1349 -0
  46. package/dist/bin/commands/security-export.js.map +7 -0
  47. package/dist/bin/commands/security-flows.js +126 -0
  48. package/dist/bin/commands/security-flows.js.map +7 -0
  49. package/dist/bin/commands/security-secrets.js +170 -0
  50. package/dist/bin/commands/security-secrets.js.map +7 -0
  51. package/dist/bin/commands/security.js +193 -0
  52. package/dist/bin/commands/security.js.map +7 -0
  53. package/dist/bin/commands/staleness.js +144 -0
  54. package/dist/bin/commands/staleness.js.map +7 -0
  55. package/dist/bin/commands/status.js +102 -2
  56. package/dist/bin/commands/status.js.map +2 -2
  57. package/dist/bin/commands/supply-chain.js +138 -0
  58. package/dist/bin/commands/supply-chain.js.map +7 -0
  59. package/dist/bin/commands/uninit.js +109 -60
  60. package/dist/bin/commands/uninit.js.map +2 -2
  61. package/dist/bin/commands/vex.js +76 -0
  62. package/dist/bin/commands/vex.js.map +7 -0
  63. package/dist/bin/commands/vuln-suppress.js +95 -0
  64. package/dist/bin/commands/vuln-suppress.js.map +7 -0
  65. package/dist/bin/commands/vulns.js +382 -0
  66. package/dist/bin/commands/vulns.js.map +7 -0
  67. package/dist/bin/installer/auto-detect.js +125 -0
  68. package/dist/bin/installer/auto-detect.js.map +7 -0
  69. package/dist/bin/installer/cli-agent.js +28 -5
  70. package/dist/bin/installer/cli-agent.js.map +2 -2
  71. package/dist/bin/installer/common.js +47 -0
  72. package/dist/bin/installer/common.js.map +2 -2
  73. package/dist/bin/installer/config-prompt.js +39 -1
  74. package/dist/bin/installer/config-prompt.js.map +2 -2
  75. package/dist/bin/installer/detect.js +309 -0
  76. package/dist/bin/installer/detect.js.map +7 -0
  77. package/dist/bin/installer/index.js +36 -1
  78. package/dist/bin/installer/index.js.map +2 -2
  79. package/dist/bin/installer/instructions.js +195 -3
  80. package/dist/bin/installer/instructions.js.map +2 -2
  81. package/dist/bin/installer/steering.js +440 -0
  82. package/dist/bin/installer/steering.js.map +2 -2
  83. package/dist/bin/installer/targets/aider.js +3 -3
  84. package/dist/bin/installer/targets/aider.js.map +2 -2
  85. package/dist/bin/installer/targets/amp.js +3 -3
  86. package/dist/bin/installer/targets/amp.js.map +2 -2
  87. package/dist/bin/installer/targets/antigravity.js +35 -6
  88. package/dist/bin/installer/targets/antigravity.js.map +2 -2
  89. package/dist/bin/installer/targets/augment.js +3 -3
  90. package/dist/bin/installer/targets/augment.js.map +2 -2
  91. package/dist/bin/installer/targets/claude.js +49 -5
  92. package/dist/bin/installer/targets/claude.js.map +2 -2
  93. package/dist/bin/installer/targets/cline.js +32 -6
  94. package/dist/bin/installer/targets/cline.js.map +2 -2
  95. package/dist/bin/installer/targets/codex.js +64 -12
  96. package/dist/bin/installer/targets/codex.js.map +2 -2
  97. package/dist/bin/installer/targets/continue.js +2 -2
  98. package/dist/bin/installer/targets/continue.js.map +2 -2
  99. package/dist/bin/installer/targets/copilot-cli.js +101 -0
  100. package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
  101. package/dist/bin/installer/targets/copilot.js +31 -5
  102. package/dist/bin/installer/targets/copilot.js.map +2 -2
  103. package/dist/bin/installer/targets/cursor.js +4 -4
  104. package/dist/bin/installer/targets/cursor.js.map +2 -2
  105. package/dist/bin/installer/targets/devin.js +2 -2
  106. package/dist/bin/installer/targets/devin.js.map +2 -2
  107. package/dist/bin/installer/targets/gemini-cli.js +2 -2
  108. package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
  109. package/dist/bin/installer/targets/generic.js +2 -14
  110. package/dist/bin/installer/targets/generic.js.map +2 -2
  111. package/dist/bin/installer/targets/goose.js +3 -3
  112. package/dist/bin/installer/targets/goose.js.map +2 -2
  113. package/dist/bin/installer/targets/index.js +250 -0
  114. package/dist/bin/installer/targets/index.js.map +2 -2
  115. package/dist/bin/installer/targets/junie.js +2 -2
  116. package/dist/bin/installer/targets/junie.js.map +2 -2
  117. package/dist/bin/installer/targets/kilo.js +2 -2
  118. package/dist/bin/installer/targets/kilo.js.map +2 -2
  119. package/dist/bin/installer/targets/kiro.js +3 -3
  120. package/dist/bin/installer/targets/kiro.js.map +2 -2
  121. package/dist/bin/installer/targets/opencode.js +2 -2
  122. package/dist/bin/installer/targets/opencode.js.map +2 -2
  123. package/dist/bin/installer/targets/openhands.js +3 -3
  124. package/dist/bin/installer/targets/openhands.js.map +2 -2
  125. package/dist/bin/installer/targets/qoder.js +91 -0
  126. package/dist/bin/installer/targets/qoder.js.map +7 -0
  127. package/dist/bin/installer/targets/qwen.js +96 -0
  128. package/dist/bin/installer/targets/qwen.js.map +7 -0
  129. package/dist/bin/installer/targets/replit.js +3 -3
  130. package/dist/bin/installer/targets/replit.js.map +2 -2
  131. package/dist/bin/installer/targets/roo.js +2 -2
  132. package/dist/bin/installer/targets/roo.js.map +2 -2
  133. package/dist/bin/installer/targets/tabnine.js +3 -3
  134. package/dist/bin/installer/targets/tabnine.js.map +2 -2
  135. package/dist/bin/installer/targets/trae.js +5 -5
  136. package/dist/bin/installer/targets/trae.js.map +2 -2
  137. package/dist/bin/installer/targets/warp.js +2 -2
  138. package/dist/bin/installer/targets/warp.js.map +2 -2
  139. package/dist/bin/installer/targets/windsurf.js +35 -6
  140. package/dist/bin/installer/targets/windsurf.js.map +2 -2
  141. package/dist/bin/kirograph.js +74 -6
  142. package/dist/bin/kirograph.js.map +3 -3
  143. package/dist/bin/progress.js +30 -0
  144. package/dist/bin/progress.js.map +2 -2
  145. package/dist/compression/naive-cost.js +25 -0
  146. package/dist/compression/naive-cost.js.map +2 -2
  147. package/dist/compression/tracker.js +91 -2
  148. package/dist/compression/tracker.js.map +2 -2
  149. package/dist/compression/types.js.map +1 -1
  150. package/dist/config.js +126 -3
  151. package/dist/config.js.map +2 -2
  152. package/dist/core/pipeline.js +92 -4
  153. package/dist/core/pipeline.js.map +2 -2
  154. package/dist/data/filters.js +105 -0
  155. package/dist/data/filters.js.map +7 -0
  156. package/dist/data/indexer.js +225 -0
  157. package/dist/data/indexer.js.map +7 -0
  158. package/dist/data/linker.js +150 -0
  159. package/dist/data/linker.js.map +7 -0
  160. package/dist/data/lint.js +109 -0
  161. package/dist/data/lint.js.map +7 -0
  162. package/dist/data/parsers/csv.js +132 -0
  163. package/dist/data/parsers/csv.js.map +7 -0
  164. package/dist/data/parsers/excel.js +88 -0
  165. package/dist/data/parsers/excel.js.map +7 -0
  166. package/dist/data/parsers/index.js +79 -0
  167. package/dist/data/parsers/index.js.map +7 -0
  168. package/dist/data/parsers/json-array.js +89 -0
  169. package/dist/data/parsers/json-array.js.map +7 -0
  170. package/dist/data/parsers/jsonl.js +84 -0
  171. package/dist/data/parsers/jsonl.js.map +7 -0
  172. package/dist/data/parsers/parquet.js +95 -0
  173. package/dist/data/parsers/parquet.js.map +7 -0
  174. package/dist/data/profiler.js +182 -0
  175. package/dist/data/profiler.js.map +7 -0
  176. package/dist/data/queries.js +512 -0
  177. package/dist/data/queries.js.map +7 -0
  178. package/dist/data/types.js +17 -0
  179. package/dist/data/types.js.map +7 -0
  180. package/dist/db/data-schema.sql +61 -0
  181. package/dist/db/database.js +67 -5
  182. package/dist/db/database.js.map +2 -2
  183. package/dist/db/memory-schema.sql +5 -1
  184. package/dist/db/schema.sql +3 -1
  185. package/dist/db/security-schema.sql +72 -0
  186. package/dist/extraction/extractor.js +81 -0
  187. package/dist/extraction/extractor.js.map +2 -2
  188. package/dist/extraction/grammars.js +32 -8
  189. package/dist/extraction/grammars.js.map +2 -2
  190. package/dist/extraction/languages.js +43 -1
  191. package/dist/extraction/languages.js.map +2 -2
  192. package/dist/extraction/notebook.js +300 -0
  193. package/dist/extraction/notebook.js.map +7 -0
  194. package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
  195. package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
  196. package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
  197. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  198. package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
  199. package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
  200. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  201. package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
  202. package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
  203. package/dist/frameworks/flutter.js +130 -0
  204. package/dist/frameworks/flutter.js.map +7 -0
  205. package/dist/frameworks/index.js +7 -1
  206. package/dist/frameworks/index.js.map +3 -3
  207. package/dist/graph/communities.js +317 -0
  208. package/dist/graph/communities.js.map +7 -0
  209. package/dist/graph/flows.js +138 -0
  210. package/dist/graph/flows.js.map +7 -0
  211. package/dist/graph/refactor.js +155 -0
  212. package/dist/graph/refactor.js.map +7 -0
  213. package/dist/index.js +1 -1
  214. package/dist/index.js.map +2 -2
  215. package/dist/mcp/cache.js +172 -0
  216. package/dist/mcp/cache.js.map +7 -0
  217. package/dist/mcp/read-modes.js +295 -0
  218. package/dist/mcp/read-modes.js.map +7 -0
  219. package/dist/mcp/server.js +2 -1
  220. package/dist/mcp/server.js.map +2 -2
  221. package/dist/mcp/tool-names.js +29 -1
  222. package/dist/mcp/tool-names.js.map +2 -2
  223. package/dist/mcp/tools.js +1588 -6
  224. package/dist/mcp/tools.js.map +3 -3
  225. package/dist/memory/database.js +32 -2
  226. package/dist/memory/database.js.map +2 -2
  227. package/dist/memory/types.js.map +1 -1
  228. package/dist/resolution/bridges/android-rn.js +298 -0
  229. package/dist/resolution/bridges/android-rn.js.map +7 -0
  230. package/dist/resolution/bridges/expo-modules.js +155 -0
  231. package/dist/resolution/bridges/expo-modules.js.map +7 -0
  232. package/dist/resolution/bridges/flutter-channel.js +385 -0
  233. package/dist/resolution/bridges/flutter-channel.js.map +7 -0
  234. package/dist/resolution/bridges/index.js +80 -0
  235. package/dist/resolution/bridges/index.js.map +7 -0
  236. package/dist/resolution/bridges/native-events.js +188 -0
  237. package/dist/resolution/bridges/native-events.js.map +7 -0
  238. package/dist/resolution/bridges/native-views.js +244 -0
  239. package/dist/resolution/bridges/native-views.js.map +7 -0
  240. package/dist/resolution/bridges/react-native.js +161 -0
  241. package/dist/resolution/bridges/react-native.js.map +7 -0
  242. package/dist/resolution/bridges/swift-objc.js +227 -0
  243. package/dist/resolution/bridges/swift-objc.js.map +7 -0
  244. package/dist/resolution/bridges/turbomodules.js +216 -0
  245. package/dist/resolution/bridges/turbomodules.js.map +7 -0
  246. package/dist/resolution/index.js +61 -2
  247. package/dist/resolution/index.js.map +2 -2
  248. package/dist/security/attack-surface.js +164 -0
  249. package/dist/security/attack-surface.js.map +7 -0
  250. package/dist/security/context-warnings.js +123 -0
  251. package/dist/security/context-warnings.js.map +7 -0
  252. package/dist/security/context-warnings.test.js +300 -0
  253. package/dist/security/context-warnings.test.js.map +7 -0
  254. package/dist/security/data-flows.js +228 -0
  255. package/dist/security/data-flows.js.map +7 -0
  256. package/dist/security/dep-confusion.js +255 -0
  257. package/dist/security/dep-confusion.js.map +7 -0
  258. package/dist/security/errors.js +51 -0
  259. package/dist/security/errors.js.map +7 -0
  260. package/dist/security/export/fix-suggestions.js +58 -0
  261. package/dist/security/export/fix-suggestions.js.map +7 -0
  262. package/dist/security/export/fix-suggestions.test.js +74 -0
  263. package/dist/security/export/fix-suggestions.test.js.map +7 -0
  264. package/dist/security/export/sbom.js +230 -0
  265. package/dist/security/export/sbom.js.map +7 -0
  266. package/dist/security/export/sbom.test.js +288 -0
  267. package/dist/security/export/sbom.test.js.map +7 -0
  268. package/dist/security/export/serialization.js +142 -0
  269. package/dist/security/export/serialization.js.map +7 -0
  270. package/dist/security/export/serialization.test.js +310 -0
  271. package/dist/security/export/serialization.test.js.map +7 -0
  272. package/dist/security/export/vex.js +220 -0
  273. package/dist/security/export/vex.js.map +7 -0
  274. package/dist/security/export/vex.test.js +278 -0
  275. package/dist/security/export/vex.test.js.map +7 -0
  276. package/dist/security/index.js +67 -0
  277. package/dist/security/index.js.map +7 -0
  278. package/dist/security/integrator-transitives.test.js +359 -0
  279. package/dist/security/integrator-transitives.test.js.map +7 -0
  280. package/dist/security/integrator.js +491 -0
  281. package/dist/security/integrator.js.map +7 -0
  282. package/dist/security/integrator.test.js +237 -0
  283. package/dist/security/integrator.test.js.map +7 -0
  284. package/dist/security/license.js +70 -0
  285. package/dist/security/license.js.map +7 -0
  286. package/dist/security/manifest/adapter.js +243 -0
  287. package/dist/security/manifest/adapter.js.map +7 -0
  288. package/dist/security/manifest/adapter.test.js +272 -0
  289. package/dist/security/manifest/adapter.test.js.map +7 -0
  290. package/dist/security/manifest/parser.js +376 -0
  291. package/dist/security/manifest/parser.js.map +7 -0
  292. package/dist/security/manifest/parser.test.js +110 -0
  293. package/dist/security/manifest/parser.test.js.map +7 -0
  294. package/dist/security/manifest/plugins/cargo.js +233 -0
  295. package/dist/security/manifest/plugins/cargo.js.map +7 -0
  296. package/dist/security/manifest/plugins/cargo.test.js +304 -0
  297. package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
  298. package/dist/security/manifest/plugins/composer.js +152 -0
  299. package/dist/security/manifest/plugins/composer.js.map +7 -0
  300. package/dist/security/manifest/plugins/go.js +146 -0
  301. package/dist/security/manifest/plugins/go.js.map +7 -0
  302. package/dist/security/manifest/plugins/go.test.js +341 -0
  303. package/dist/security/manifest/plugins/go.test.js.map +7 -0
  304. package/dist/security/manifest/plugins/gradle.js +159 -0
  305. package/dist/security/manifest/plugins/gradle.js.map +7 -0
  306. package/dist/security/manifest/plugins/hex.js +159 -0
  307. package/dist/security/manifest/plugins/hex.js.map +7 -0
  308. package/dist/security/manifest/plugins/maven.js +128 -0
  309. package/dist/security/manifest/plugins/maven.js.map +7 -0
  310. package/dist/security/manifest/plugins/maven.test.js +389 -0
  311. package/dist/security/manifest/plugins/maven.test.js.map +7 -0
  312. package/dist/security/manifest/plugins/npm.js +284 -0
  313. package/dist/security/manifest/plugins/npm.js.map +7 -0
  314. package/dist/security/manifest/plugins/npm.test.js +298 -0
  315. package/dist/security/manifest/plugins/npm.test.js.map +7 -0
  316. package/dist/security/manifest/plugins/nuget.js +186 -0
  317. package/dist/security/manifest/plugins/nuget.js.map +7 -0
  318. package/dist/security/manifest/plugins/pip.js +123 -0
  319. package/dist/security/manifest/plugins/pip.js.map +7 -0
  320. package/dist/security/manifest/plugins/pip.test.js +208 -0
  321. package/dist/security/manifest/plugins/pip.test.js.map +7 -0
  322. package/dist/security/manifest/plugins/pubspec.js +212 -0
  323. package/dist/security/manifest/plugins/pubspec.js.map +7 -0
  324. package/dist/security/manifest/plugins/pyproject.js +261 -0
  325. package/dist/security/manifest/plugins/pyproject.js.map +7 -0
  326. package/dist/security/manifest/plugins/rubygems.js +185 -0
  327. package/dist/security/manifest/plugins/rubygems.js.map +7 -0
  328. package/dist/security/manifest/plugins/swift.js +200 -0
  329. package/dist/security/manifest/plugins/swift.js.map +7 -0
  330. package/dist/security/owasp.js +104 -0
  331. package/dist/security/owasp.js.map +7 -0
  332. package/dist/security/pipeline.js +125 -0
  333. package/dist/security/pipeline.js.map +7 -0
  334. package/dist/security/reachability.js +276 -0
  335. package/dist/security/reachability.js.map +7 -0
  336. package/dist/security/reachability.test.js +394 -0
  337. package/dist/security/reachability.test.js.map +7 -0
  338. package/dist/security/remediation.js +126 -0
  339. package/dist/security/remediation.js.map +7 -0
  340. package/dist/security/secrets.js +176 -0
  341. package/dist/security/secrets.js.map +7 -0
  342. package/dist/security/staleness.js +231 -0
  343. package/dist/security/staleness.js.map +7 -0
  344. package/dist/security/supply-chain.js +301 -0
  345. package/dist/security/supply-chain.js.map +7 -0
  346. package/dist/security/suppressions.js +106 -0
  347. package/dist/security/suppressions.js.map +7 -0
  348. package/dist/security/types.js +17 -0
  349. package/dist/security/types.js.map +7 -0
  350. package/dist/security/vuln/client.js +355 -0
  351. package/dist/security/vuln/client.js.map +7 -0
  352. package/dist/security/vuln/client.test.js +288 -0
  353. package/dist/security/vuln/client.test.js.map +7 -0
  354. package/dist/security/vuln/epss-client.js +95 -0
  355. package/dist/security/vuln/epss-client.js.map +7 -0
  356. package/dist/security/vuln/index.js +29 -0
  357. package/dist/security/vuln/index.js.map +7 -0
  358. package/dist/security/vuln/osv-adapter.js +321 -0
  359. package/dist/security/vuln/osv-adapter.js.map +7 -0
  360. package/dist/security/vuln/osv-adapter.test.js +391 -0
  361. package/dist/security/vuln/osv-adapter.test.js.map +7 -0
  362. package/dist/security/vuln/types.js +17 -0
  363. package/dist/security/vuln/types.js.map +7 -0
  364. package/dist/types.js.map +2 -2
  365. package/package.json +5 -2
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/security/manifest/plugins/pip.test.ts"],
4
+ "sourcesContent": ["/**\n * Unit tests for the pip security manifest plugin.\n */\nimport { describe, it, expect, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { parsePipManifest } from './pip';\n\ndescribe('parsePipManifest', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kirograph-pip-test-'));\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n function writeRequirements(content: string, filename = 'requirements.txt'): string {\n const filePath = path.join(tmpDir, filename);\n fs.writeFileSync(filePath, content);\n return filePath;\n }\n\n it('extracts packages with == constraint and resolves exact version', async () => {\n const manifestPath = writeRequirements('flask==2.3.0\\nrequests==2.28.1\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n const flask = deps.find(d => d.name === 'flask');\n expect(flask).toBeDefined();\n expect(flask!.declaredConstraint).toBe('==2.3.0');\n expect(flask!.resolvedVersion).toBe('2.3.0');\n expect(flask!.scope).toBe('production');\n expect(flask!.ecosystem).toBe('pypi');\n\n const requests = deps.find(d => d.name === 'requests');\n expect(requests).toBeDefined();\n expect(requests!.declaredConstraint).toBe('==2.28.1');\n expect(requests!.resolvedVersion).toBe('2.28.1');\n });\n\n it('extracts packages with >= constraint (no resolved version)', async () => {\n const manifestPath = writeRequirements('requests>=2.28\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].name).toBe('requests');\n expect(deps[0].declaredConstraint).toBe('>=2.28');\n expect(deps[0].resolvedVersion).toBeUndefined();\n });\n\n it('extracts packages with ~= constraint', async () => {\n const manifestPath = writeRequirements('django~=4.2\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].name).toBe('django');\n expect(deps[0].declaredConstraint).toBe('~=4.2');\n expect(deps[0].resolvedVersion).toBeUndefined();\n });\n\n it('extracts packages with no version constraint', async () => {\n const manifestPath = writeRequirements('numpy\\nscipy\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n expect(deps[0].name).toBe('numpy');\n expect(deps[0].declaredConstraint).toBe('');\n expect(deps[0].resolvedVersion).toBeUndefined();\n expect(deps[1].name).toBe('scipy');\n });\n\n it('skips comment lines', async () => {\n const manifestPath = writeRequirements(\n '# This is a comment\\nflask==2.3.0\\n# Another comment\\nrequests>=2.28\\n',\n );\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n expect(deps.map(d => d.name)).toEqual(['flask', 'requests']);\n });\n\n it('skips empty lines', async () => {\n const manifestPath = writeRequirements('flask==2.3.0\\n\\n\\nrequests>=2.28\\n\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n });\n\n it('skips pip option lines (-r, -c, -e, --index-url, --extra-index-url)', async () => {\n const manifestPath = writeRequirements(\n '-r base.txt\\n-c constraints.txt\\n-e git+https://github.com/user/repo.git\\n--index-url https://pypi.org/simple\\n--extra-index-url https://private.pypi.org/simple\\nflask==2.3.0\\n',\n );\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].name).toBe('flask');\n });\n\n it('strips environment markers', async () => {\n const manifestPath = writeRequirements(\n 'pywin32>=300; sys_platform == \"win32\"\\ncolorama>=0.4; os_name == \"nt\"\\nflask==2.3.0\\n',\n );\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(3);\n const pywin32 = deps.find(d => d.name === 'pywin32');\n expect(pywin32).toBeDefined();\n expect(pywin32!.declaredConstraint).toBe('>=300');\n\n const colorama = deps.find(d => d.name === 'colorama');\n expect(colorama).toBeDefined();\n expect(colorama!.declaredConstraint).toBe('>=0.4');\n });\n\n it('handles packages with extras (e.g. package[extra]>=1.0)', async () => {\n const manifestPath = writeRequirements('requests[security]>=2.28.0\\ncelery[redis]==5.3.0\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n const requests = deps.find(d => d.name === 'requests');\n expect(requests).toBeDefined();\n expect(requests!.declaredConstraint).toBe('>=2.28.0');\n\n const celery = deps.find(d => d.name === 'celery');\n expect(celery).toBeDefined();\n expect(celery!.declaredConstraint).toBe('==5.3.0');\n expect(celery!.resolvedVersion).toBe('5.3.0');\n });\n\n it('normalizes package names (PEP 503)', async () => {\n const manifestPath = writeRequirements(\n 'Flask==2.3.0\\nPyYAML>=6.0\\nmy_package==1.0.0\\nAnother.Package>=2.0\\n',\n );\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(4);\n expect(deps.map(d => d.name)).toEqual([\n 'flask',\n 'pyyaml',\n 'my-package',\n 'another-package',\n ]);\n });\n\n it('all dependencies have production scope', async () => {\n const manifestPath = writeRequirements('flask==2.3.0\\npytest==7.0.0\\nmypy>=1.0\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(3);\n expect(deps.every(d => d.scope === 'production')).toBe(true);\n });\n\n it('all dependencies have pypi ecosystem', async () => {\n const manifestPath = writeRequirements('flask==2.3.0\\ndjango~=4.2\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps.every(d => d.ecosystem === 'pypi')).toBe(true);\n });\n\n it('sets sourceManifest as relative path', async () => {\n const subDir = path.join(tmpDir, 'services', 'api');\n fs.mkdirSync(subDir, { recursive: true });\n const filePath = path.join(subDir, 'requirements.txt');\n fs.writeFileSync(filePath, 'flask==2.3.0\\n');\n\n const deps = await parsePipManifest(filePath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].sourceManifest).toBe('services/api/requirements.txt');\n });\n\n it('returns empty array for non-existent file', async () => {\n const deps = await parsePipManifest(\n path.join(tmpDir, 'nonexistent.txt'),\n tmpDir,\n );\n expect(deps).toEqual([]);\n });\n\n it('handles inline comments', async () => {\n const manifestPath = writeRequirements(\n 'flask==2.3.0 # web framework\\nrequests>=2.28 # HTTP library\\n',\n );\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n expect(deps[0].declaredConstraint).toBe('==2.3.0');\n expect(deps[1].declaredConstraint).toBe('>=2.28');\n });\n\n it('handles compound version constraints (e.g. >=1.0,<2.0)', async () => {\n const manifestPath = writeRequirements('flask>=2.0,<3.0\\nrequests>=2.28,!=2.29.0\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n expect(deps[0].name).toBe('flask');\n expect(deps[0].declaredConstraint).toBe('>=2.0,<3.0');\n expect(deps[0].resolvedVersion).toBeUndefined();\n\n expect(deps[1].name).toBe('requests');\n expect(deps[1].declaredConstraint).toBe('>=2.28,!=2.29.0');\n });\n\n it('handles != constraint', async () => {\n const manifestPath = writeRequirements('flask!=2.2.0\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].declaredConstraint).toBe('!=2.2.0');\n expect(deps[0].resolvedVersion).toBeUndefined();\n });\n\n it('handles < and > constraints', async () => {\n const manifestPath = writeRequirements('flask>2.0\\ndjango<5.0\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n expect(deps[0].declaredConstraint).toBe('>2.0');\n expect(deps[1].declaredConstraint).toBe('<5.0');\n });\n\n it('handles <= constraint', async () => {\n const manifestPath = writeRequirements('flask<=2.3.0\\n');\n\n const deps = await parsePipManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].declaredConstraint).toBe('<=2.3.0');\n });\n});\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAGA,oBAA4D;AAC5D,SAAoB;AACpB,WAAsB;AACtB,SAAoB;AACpB,iBAAiC;AAAA,IAEjC,wBAAS,oBAAoB,MAAM;AACjC,MAAI;AAEJ,gCAAW,MAAM;AACf,aAAS,GAAG,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,qBAAqB,CAAC;AAAA,EACvE,CAAC;AAED,+BAAU,MAAM;AACd,OAAG,OAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACpD,CAAC;AAED,WAAS,kBAAkB,SAAiB,WAAW,oBAA4B;AACjF,UAAM,WAAW,KAAK,KAAK,QAAQ,QAAQ;AAC3C,OAAG,cAAc,UAAU,OAAO;AAClC,WAAO;AAAA,EACT;AAEA,wBAAG,mEAAmE,YAAY;AAChF,UAAM,eAAe,kBAAkB,kCAAkC;AAEzE,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,UAAM,QAAQ,KAAK,KAAK,OAAK,EAAE,SAAS,OAAO;AAC/C,8BAAO,KAAK,EAAE,YAAY;AAC1B,8BAAO,MAAO,kBAAkB,EAAE,KAAK,SAAS;AAChD,8BAAO,MAAO,eAAe,EAAE,KAAK,OAAO;AAC3C,8BAAO,MAAO,KAAK,EAAE,KAAK,YAAY;AACtC,8BAAO,MAAO,SAAS,EAAE,KAAK,MAAM;AAEpC,UAAM,WAAW,KAAK,KAAK,OAAK,EAAE,SAAS,UAAU;AACrD,8BAAO,QAAQ,EAAE,YAAY;AAC7B,8BAAO,SAAU,kBAAkB,EAAE,KAAK,UAAU;AACpD,8BAAO,SAAU,eAAe,EAAE,KAAK,QAAQ;AAAA,EACjD,CAAC;AAED,wBAAG,8DAA8D,YAAY;AAC3E,UAAM,eAAe,kBAAkB,kBAAkB;AAEzD,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,UAAU;AACpC,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,QAAQ;AAChD,8BAAO,KAAK,CAAC,EAAE,eAAe,EAAE,cAAc;AAAA,EAChD,CAAC;AAED,wBAAG,wCAAwC,YAAY;AACrD,UAAM,eAAe,kBAAkB,eAAe;AAEtD,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,QAAQ;AAClC,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,OAAO;AAC/C,8BAAO,KAAK,CAAC,EAAE,eAAe,EAAE,cAAc;AAAA,EAChD,CAAC;AAED,wBAAG,gDAAgD,YAAY;AAC7D,UAAM,eAAe,kBAAkB,gBAAgB;AAEvD,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,OAAO;AACjC,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE;AAC1C,8BAAO,KAAK,CAAC,EAAE,eAAe,EAAE,cAAc;AAC9C,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,OAAO;AAAA,EACnC,CAAC;AAED,wBAAG,uBAAuB,YAAY;AACpC,UAAM,eAAe;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,IAAI,OAAK,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,SAAS,UAAU,CAAC;AAAA,EAC7D,CAAC;AAED,wBAAG,qBAAqB,YAAY;AAClC,UAAM,eAAe,kBAAkB,sCAAsC;AAE7E,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAAA,EAC7B,CAAC;AAED,wBAAG,uEAAuE,YAAY;AACpF,UAAM,eAAe;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,OAAO;AAAA,EACnC,CAAC;AAED,wBAAG,8BAA8B,YAAY;AAC3C,UAAM,eAAe;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,UAAM,UAAU,KAAK,KAAK,OAAK,EAAE,SAAS,SAAS;AACnD,8BAAO,OAAO,EAAE,YAAY;AAC5B,8BAAO,QAAS,kBAAkB,EAAE,KAAK,OAAO;AAEhD,UAAM,WAAW,KAAK,KAAK,OAAK,EAAE,SAAS,UAAU;AACrD,8BAAO,QAAQ,EAAE,YAAY;AAC7B,8BAAO,SAAU,kBAAkB,EAAE,KAAK,OAAO;AAAA,EACnD,CAAC;AAED,wBAAG,2DAA2D,YAAY;AACxE,UAAM,eAAe,kBAAkB,oDAAoD;AAE3F,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,UAAM,WAAW,KAAK,KAAK,OAAK,EAAE,SAAS,UAAU;AACrD,8BAAO,QAAQ,EAAE,YAAY;AAC7B,8BAAO,SAAU,kBAAkB,EAAE,KAAK,UAAU;AAEpD,UAAM,SAAS,KAAK,KAAK,OAAK,EAAE,SAAS,QAAQ;AACjD,8BAAO,MAAM,EAAE,YAAY;AAC3B,8BAAO,OAAQ,kBAAkB,EAAE,KAAK,SAAS;AACjD,8BAAO,OAAQ,eAAe,EAAE,KAAK,OAAO;AAAA,EAC9C,CAAC;AAED,wBAAG,sCAAsC,YAAY;AACnD,UAAM,eAAe;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,IAAI,OAAK,EAAE,IAAI,CAAC,EAAE,QAAQ;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,wBAAG,0CAA0C,YAAY;AACvD,UAAM,eAAe,kBAAkB,0CAA0C;AAEjF,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,MAAM,OAAK,EAAE,UAAU,YAAY,CAAC,EAAE,KAAK,IAAI;AAAA,EAC7D,CAAC;AAED,wBAAG,wCAAwC,YAAY;AACrD,UAAM,eAAe,kBAAkB,6BAA6B;AAEpE,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,KAAK,MAAM,OAAK,EAAE,cAAc,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,EAC3D,CAAC;AAED,wBAAG,wCAAwC,YAAY;AACrD,UAAM,SAAS,KAAK,KAAK,QAAQ,YAAY,KAAK;AAClD,OAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACxC,UAAM,WAAW,KAAK,KAAK,QAAQ,kBAAkB;AACrD,OAAG,cAAc,UAAU,gBAAgB;AAE3C,UAAM,OAAO,UAAM,6BAAiB,UAAU,MAAM;AAEpD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,cAAc,EAAE,KAAK,+BAA+B;AAAA,EACrE,CAAC;AAED,wBAAG,6CAA6C,YAAY;AAC1D,UAAM,OAAO,UAAM;AAAA,MACjB,KAAK,KAAK,QAAQ,iBAAiB;AAAA,MACnC;AAAA,IACF;AACA,8BAAO,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,EACzB,CAAC;AAED,wBAAG,2BAA2B,YAAY;AACxC,UAAM,eAAe;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,SAAS;AACjD,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,QAAQ;AAAA,EAClD,CAAC;AAED,wBAAG,0DAA0D,YAAY;AACvE,UAAM,eAAe,kBAAkB,4CAA4C;AAEnF,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,OAAO;AACjC,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,YAAY;AACpD,8BAAO,KAAK,CAAC,EAAE,eAAe,EAAE,cAAc;AAE9C,8BAAO,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,UAAU;AACpC,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,iBAAiB;AAAA,EAC3D,CAAC;AAED,wBAAG,yBAAyB,YAAY;AACtC,UAAM,eAAe,kBAAkB,gBAAgB;AAEvD,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,SAAS;AACjD,8BAAO,KAAK,CAAC,EAAE,eAAe,EAAE,cAAc;AAAA,EAChD,CAAC;AAED,wBAAG,+BAA+B,YAAY;AAC5C,UAAM,eAAe,kBAAkB,yBAAyB;AAEhE,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,MAAM;AAC9C,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,MAAM;AAAA,EAChD,CAAC;AAED,wBAAG,yBAAyB,YAAY;AACtC,UAAM,eAAe,kBAAkB,gBAAgB;AAEvD,UAAM,OAAO,UAAM,6BAAiB,cAAc,MAAM;AAExD,8BAAO,IAAI,EAAE,aAAa,CAAC;AAC3B,8BAAO,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,SAAS;AAAA,EACnD,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var pubspec_exports = {};
30
+ __export(pubspec_exports, {
31
+ parsePubspecManifest: () => parsePubspecManifest
32
+ });
33
+ module.exports = __toCommonJS(pubspec_exports);
34
+ var fs = __toESM(require("fs"));
35
+ var path = __toESM(require("path"));
36
+ var import_errors = require("../../../errors");
37
+ async function parsePubspecManifest(manifestPath, projectRoot) {
38
+ const manifestDir = path.dirname(manifestPath);
39
+ const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\/g, "/");
40
+ let content;
41
+ try {
42
+ content = fs.readFileSync(manifestPath, "utf8");
43
+ } catch (err) {
44
+ (0, import_errors.logWarn)(`[sec:pub] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);
45
+ return [];
46
+ }
47
+ const resolvedVersions = loadResolvedVersions(manifestDir);
48
+ const license = extractPubspecLicense(content);
49
+ const dependencies = [];
50
+ const sections = [
51
+ { key: "dependencies", scope: "production" },
52
+ { key: "dev_dependencies", scope: "development" }
53
+ ];
54
+ for (const { key, scope } of sections) {
55
+ const sectionDeps = extractSectionDependencies(content, key, relativeManifest);
56
+ for (const dep of sectionDeps) {
57
+ const resolvedVersion = resolvedVersions.get(dep.name);
58
+ dependencies.push({
59
+ name: dep.name,
60
+ declaredConstraint: dep.constraint,
61
+ resolvedVersion,
62
+ scope,
63
+ ecosystem: "pub",
64
+ sourceManifest: relativeManifest,
65
+ ...license !== void 0 ? { license } : {}
66
+ });
67
+ }
68
+ }
69
+ return dependencies;
70
+ }
71
+ function extractSectionDependencies(content, sectionKey, relativeManifest) {
72
+ const deps = [];
73
+ const lines = content.split("\n");
74
+ const headerPattern = new RegExp(`^${escapeRegex(sectionKey)}\\s*:\\s*$`);
75
+ let inSection = false;
76
+ let i = 0;
77
+ while (i < lines.length) {
78
+ const line = lines[i];
79
+ const trimmed = line.trimEnd();
80
+ if (!inSection) {
81
+ if (headerPattern.test(trimmed)) {
82
+ inSection = true;
83
+ }
84
+ i++;
85
+ continue;
86
+ }
87
+ if (trimmed !== "" && !/^\s/.test(trimmed)) {
88
+ break;
89
+ }
90
+ if (trimmed === "") {
91
+ i++;
92
+ continue;
93
+ }
94
+ const entryMatch = trimmed.match(/^ ([a-zA-Z0-9_][a-zA-Z0-9_.-]*):\s*(.*)$/);
95
+ if (!entryMatch) {
96
+ i++;
97
+ continue;
98
+ }
99
+ const pkgName = entryMatch[1];
100
+ const valueOnSameLine = entryMatch[2].trim();
101
+ const nextLine = i + 1 < lines.length ? lines[i + 1] : "";
102
+ const isBlockMapping = nextLine !== "" && /^ \S/.test(nextLine);
103
+ if (isBlockMapping) {
104
+ i++;
105
+ while (i < lines.length) {
106
+ const subLine = lines[i];
107
+ if (subLine.trimEnd() === "" || /^ /.test(subLine)) {
108
+ i++;
109
+ } else {
110
+ break;
111
+ }
112
+ }
113
+ continue;
114
+ }
115
+ if (shouldSkipEntry(pkgName)) {
116
+ i++;
117
+ continue;
118
+ }
119
+ if (!isValidPackageName(pkgName)) {
120
+ (0, import_errors.logWarn)(`[sec:pub] Invalid package name "${pkgName}" in ${relativeManifest} \u2014 skipping`);
121
+ i++;
122
+ continue;
123
+ }
124
+ const constraint = parseConstraintValue(valueOnSameLine);
125
+ deps.push({ name: pkgName, constraint });
126
+ i++;
127
+ }
128
+ return deps;
129
+ }
130
+ function parseConstraintValue(value) {
131
+ if (!value || value === "" || value.toLowerCase() === "any") return "*";
132
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
133
+ value = value.slice(1, -1).trim();
134
+ }
135
+ return value || "*";
136
+ }
137
+ function shouldSkipEntry(name) {
138
+ if (name === "sdk") return true;
139
+ if (name === "flutter") return true;
140
+ return false;
141
+ }
142
+ function isValidPackageName(name) {
143
+ if (!name || typeof name !== "string") return false;
144
+ if (name.length > 128) return false;
145
+ return /^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/.test(name);
146
+ }
147
+ function loadResolvedVersions(manifestDir) {
148
+ const map = /* @__PURE__ */ new Map();
149
+ const lockPath = path.join(manifestDir, "pubspec.lock");
150
+ if (!fs.existsSync(lockPath)) {
151
+ return map;
152
+ }
153
+ try {
154
+ const lockContent = fs.readFileSync(lockPath, "utf8");
155
+ extractFromPubspecLock(lockContent, map);
156
+ } catch (err) {
157
+ (0, import_errors.logWarn)(`[sec:pub] Failed to parse pubspec.lock: ${err instanceof Error ? err.message : String(err)}`);
158
+ }
159
+ return map;
160
+ }
161
+ function extractFromPubspecLock(content, map) {
162
+ const lines = content.split("\n");
163
+ let inPackagesSection = false;
164
+ let currentPackage = null;
165
+ for (const line of lines) {
166
+ const trimmed = line.trimEnd();
167
+ if (trimmed === "packages:") {
168
+ inPackagesSection = true;
169
+ currentPackage = null;
170
+ continue;
171
+ }
172
+ if (inPackagesSection && trimmed !== "" && !/^\s/.test(trimmed)) {
173
+ inPackagesSection = false;
174
+ currentPackage = null;
175
+ continue;
176
+ }
177
+ if (!inPackagesSection) continue;
178
+ const pkgNameMatch = trimmed.match(/^ ([a-zA-Z0-9_][a-zA-Z0-9_.-]*):\s*$/);
179
+ if (pkgNameMatch) {
180
+ currentPackage = pkgNameMatch[1];
181
+ continue;
182
+ }
183
+ if (currentPackage) {
184
+ const versionMatch = trimmed.match(/^ version:\s*["']?([^"'\s]+)["']?\s*$/);
185
+ if (versionMatch) {
186
+ if (!map.has(currentPackage)) {
187
+ map.set(currentPackage, versionMatch[1]);
188
+ }
189
+ currentPackage = null;
190
+ }
191
+ }
192
+ }
193
+ }
194
+ function escapeRegex(str) {
195
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
196
+ }
197
+ function extractPubspecLicense(content) {
198
+ const match = content.match(/^license:\s*(.+)$/m);
199
+ if (match && match[1].trim() !== "") {
200
+ let value = match[1].trim();
201
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
202
+ value = value.slice(1, -1).trim();
203
+ }
204
+ return value || void 0;
205
+ }
206
+ return void 0;
207
+ }
208
+ // Annotate the CommonJS export names for ESM import in node:
209
+ 0 && (module.exports = {
210
+ parsePubspecManifest
211
+ });
212
+ //# sourceMappingURL=pubspec.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/security/manifest/plugins/pubspec.ts"],
4
+ "sourcesContent": ["/**\n * Dart/Flutter pub Version Extraction Plugin for KiroGraph-Sec\n *\n * Parses pubspec.yaml manifests to extract Dart package declarations with\n * version constraints, scopes, and resolved versions from pubspec.lock.\n *\n * Uses lightweight regex-based YAML parsing \u2014 no external YAML library required.\n *\n * Handles:\n * - `dependencies:` section \u2192 'production' scope\n * - `dev_dependencies:` section \u2192 'development' scope\n * - Version formats: `^1.0.0`, `\">=1.0.0 <2.0.0\"`, `any`\n * - Skips SDK entries (`sdk:`), `flutter:`, path deps, and git deps\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ParsedDependency } from '../../types';\nimport { logWarn } from '../../../errors';\n\n/**\n * Resolved version map: package name \u2192 resolved version string.\n * Built from pubspec.lock.\n */\ntype ResolvedVersionMap = Map<string, string>;\n\n/**\n * Parse a pubspec.yaml manifest and extract package declarations with\n * version constraints, scopes, and resolved versions from pubspec.lock.\n *\n * @param manifestPath - Absolute path to the pubspec.yaml file\n * @param projectRoot - Absolute path to the project root directory\n * @returns Array of parsed dependencies with version and scope information\n */\nexport async function parsePubspecManifest(\n manifestPath: string,\n projectRoot: string,\n): Promise<ParsedDependency[]> {\n const manifestDir = path.dirname(manifestPath);\n const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\\\/g, '/');\n\n // Read the pubspec.yaml content\n let content: string;\n try {\n content = fs.readFileSync(manifestPath, 'utf8');\n } catch (err) {\n logWarn(`[sec:pub] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);\n return [];\n }\n\n // Attempt to load resolved versions from pubspec.lock\n const resolvedVersions = loadResolvedVersions(manifestDir);\n\n // Extract the license field if present\n const license = extractPubspecLicense(content);\n\n const dependencies: ParsedDependency[] = [];\n\n // Process `dependencies` (production) and `dev_dependencies` (development)\n const sections: Array<{ key: string; scope: ParsedDependency['scope'] }> = [\n { key: 'dependencies', scope: 'production' },\n { key: 'dev_dependencies', scope: 'development' },\n ];\n\n for (const { key, scope } of sections) {\n const sectionDeps = extractSectionDependencies(content, key, relativeManifest);\n for (const dep of sectionDeps) {\n const resolvedVersion = resolvedVersions.get(dep.name);\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion,\n scope,\n ecosystem: 'pub',\n sourceManifest: relativeManifest,\n ...(license !== undefined ? { license } : {}),\n });\n }\n }\n\n return dependencies;\n}\n\n/**\n * A raw dependency entry extracted from a pubspec.yaml section.\n */\ninterface RawDependency {\n name: string;\n constraint: string;\n}\n\n/**\n * Extract dependencies from a specific top-level section of a pubspec.yaml file.\n * Uses indentation-based parsing to determine section boundaries.\n *\n * Section entries take one of three forms:\n * - ` package_name: ^1.0.0` (inline scalar version)\n * - ` package_name: \">=1.0.0 <2.0.0\"` (quoted version)\n * - ` package_name: any` (any version)\n * - ` package_name:` (block mapping \u2014 path/git/sdk dep)\n * ` path: ../local`\n *\n * Entries with sub-keys (block mappings) are skipped as non-registry deps.\n */\nfunction extractSectionDependencies(\n content: string,\n sectionKey: string,\n relativeManifest: string,\n): RawDependency[] {\n const deps: RawDependency[] = [];\n const lines = content.split('\\n');\n\n // Find the section header line (at column 0, no indent)\n const headerPattern = new RegExp(`^${escapeRegex(sectionKey)}\\\\s*:\\\\s*$`);\n let inSection = false;\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n const trimmed = line.trimEnd();\n\n // Detect section header\n if (!inSection) {\n if (headerPattern.test(trimmed)) {\n inSection = true;\n }\n i++;\n continue;\n }\n\n // Exit section when we encounter another top-level key (no leading whitespace)\n if (trimmed !== '' && !/^\\s/.test(trimmed)) {\n break;\n }\n\n // Skip blank lines inside section\n if (trimmed === '') {\n i++;\n continue;\n }\n\n // Match a 2-space-indented package entry: ` package_name: ...`\n const entryMatch = trimmed.match(/^ ([a-zA-Z0-9_][a-zA-Z0-9_.-]*):\\s*(.*)$/);\n if (!entryMatch) {\n i++;\n continue;\n }\n\n const pkgName = entryMatch[1];\n const valueOnSameLine = entryMatch[2].trim();\n\n // Check if the next line has deeper indentation (block mapping \u2192 skip)\n const nextLine = i + 1 < lines.length ? lines[i + 1] : '';\n const isBlockMapping = nextLine !== '' && /^ \\S/.test(nextLine);\n\n if (isBlockMapping) {\n // Skip \u2014 path/git/sdk dependency; advance past the block\n i++;\n while (i < lines.length) {\n const subLine = lines[i];\n if (subLine.trimEnd() === '' || /^ /.test(subLine)) {\n i++;\n } else {\n break;\n }\n }\n continue;\n }\n\n // Skip SDK and flutter pseudo-packages\n if (shouldSkipEntry(pkgName)) {\n i++;\n continue;\n }\n\n if (!isValidPackageName(pkgName)) {\n logWarn(`[sec:pub] Invalid package name \"${pkgName}\" in ${relativeManifest} \u2014 skipping`);\n i++;\n continue;\n }\n\n const constraint = parseConstraintValue(valueOnSameLine);\n deps.push({ name: pkgName, constraint });\n i++;\n }\n\n return deps;\n}\n\n/**\n * Parse a pubspec.yaml dependency version value string.\n *\n * Handles:\n * - `^1.0.0` \u2192 `^1.0.0`\n * - `\">=1.0.0 <2.0.0\"` \u2192 `>=1.0.0 <2.0.0` (quotes stripped)\n * - `'>=1.0.0 <2.0.0'` \u2192 `>=1.0.0 <2.0.0`\n * - `any` \u2192 `*`\n * - empty \u2192 `*`\n */\nfunction parseConstraintValue(value: string): string {\n if (!value || value === '' || value.toLowerCase() === 'any') return '*';\n\n // Strip surrounding quotes\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1).trim();\n }\n\n return value || '*';\n}\n\n/**\n * Determine whether a pubspec.yaml dependency key should be skipped.\n */\nfunction shouldSkipEntry(name: string): boolean {\n if (name === 'sdk') return true;\n if (name === 'flutter') return true;\n return false;\n}\n\n/**\n * Validate that a pub package name follows Dart naming conventions.\n * Package names must be lowercase, with underscores, not hyphens.\n */\nfunction isValidPackageName(name: string): boolean {\n if (!name || typeof name !== 'string') return false;\n if (name.length > 128) return false;\n return /^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/.test(name);\n}\n\n/**\n * Attempt to load resolved versions from pubspec.lock in the given directory.\n * Returns an empty map if pubspec.lock is not available.\n *\n * pubspec.lock YAML format:\n * ```yaml\n * packages:\n * http:\n * dependency: \"direct main\"\n * description:\n * name: http\n * url: \"https://pub.dartlang.org\"\n * version: \"0.13.5\"\n * test:\n * dependency: \"direct dev\"\n * version: \"1.21.4\"\n * ```\n */\nfunction loadResolvedVersions(manifestDir: string): ResolvedVersionMap {\n const map: ResolvedVersionMap = new Map();\n\n const lockPath = path.join(manifestDir, 'pubspec.lock');\n if (!fs.existsSync(lockPath)) {\n return map;\n }\n\n try {\n const lockContent = fs.readFileSync(lockPath, 'utf8');\n extractFromPubspecLock(lockContent, map);\n } catch (err) {\n logWarn(`[sec:pub] Failed to parse pubspec.lock: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return map;\n}\n\n/**\n * Extract resolved versions from pubspec.lock content.\n *\n * The lock file is a YAML document. We use regex-based parsing to avoid\n * introducing a YAML library dependency. For each package block under\n * `packages:`, we find its `version:` entry.\n */\nfunction extractFromPubspecLock(content: string, map: ResolvedVersionMap): void {\n const lines = content.split('\\n');\n let inPackagesSection = false;\n let currentPackage: string | null = null;\n\n for (const line of lines) {\n const trimmed = line.trimEnd();\n\n // Detect top-level `packages:` section\n if (trimmed === 'packages:') {\n inPackagesSection = true;\n currentPackage = null;\n continue;\n }\n\n // Exit packages section if we hit another top-level key\n if (inPackagesSection && trimmed !== '' && !/^\\s/.test(trimmed)) {\n inPackagesSection = false;\n currentPackage = null;\n continue;\n }\n\n if (!inPackagesSection) continue;\n\n // Package name entry: ` package_name:` (2-space indent)\n const pkgNameMatch = trimmed.match(/^ ([a-zA-Z0-9_][a-zA-Z0-9_.-]*):\\s*$/);\n if (pkgNameMatch) {\n currentPackage = pkgNameMatch[1];\n continue;\n }\n\n // Version entry: ` version: \"1.2.3\"` (4-space indent)\n if (currentPackage) {\n const versionMatch = trimmed.match(/^ version:\\s*[\"']?([^\"'\\s]+)[\"']?\\s*$/);\n if (versionMatch) {\n if (!map.has(currentPackage)) {\n map.set(currentPackage, versionMatch[1]);\n }\n currentPackage = null;\n }\n }\n }\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Extract the `license:` field from pubspec.yaml content.\n * Handles: `license: MIT` (top-level scalar field)\n */\nfunction extractPubspecLicense(content: string): string | undefined {\n const match = content.match(/^license:\\s*(.+)$/m);\n if (match && match[1].trim() !== '') {\n // Strip surrounding quotes if present\n let value = match[1].trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1).trim();\n }\n return value || undefined;\n }\n return undefined;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var pyproject_exports = {};
30
+ __export(pyproject_exports, {
31
+ parsePyprojectManifest: () => parsePyprojectManifest
32
+ });
33
+ module.exports = __toCommonJS(pyproject_exports);
34
+ var fs = __toESM(require("fs"));
35
+ var path = __toESM(require("path"));
36
+ var import_errors = require("../../../errors");
37
+ async function parsePyprojectManifest(manifestPath, projectRoot) {
38
+ const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\/g, "/");
39
+ let content;
40
+ try {
41
+ content = fs.readFileSync(manifestPath, "utf8");
42
+ } catch (err) {
43
+ (0, import_errors.logWarn)(`[sec:pyproject] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);
44
+ return [];
45
+ }
46
+ const manifestDir = path.dirname(manifestPath);
47
+ const resolvedVersions = loadResolvedVersions(manifestDir);
48
+ const license = extractPyprojectLicense(content);
49
+ const dependencies = [];
50
+ const pep621Deps = extractPep621Dependencies(content, relativeManifest);
51
+ for (const dep of pep621Deps) {
52
+ dependencies.push({
53
+ name: dep.name,
54
+ declaredConstraint: dep.constraint,
55
+ resolvedVersion: resolvedVersions.get(dep.name.toLowerCase()),
56
+ scope: dep.scope,
57
+ ecosystem: "pypi",
58
+ sourceManifest: relativeManifest,
59
+ ...license !== void 0 ? { license } : {}
60
+ });
61
+ }
62
+ if (dependencies.length === 0 || hasPoetrySection(content)) {
63
+ const poetryDeps = extractPoetryDependencies(content, relativeManifest);
64
+ for (const dep of poetryDeps) {
65
+ if (!dependencies.find((d) => d.name === dep.name)) {
66
+ dependencies.push({
67
+ name: dep.name,
68
+ declaredConstraint: dep.constraint,
69
+ resolvedVersion: resolvedVersions.get(dep.name.toLowerCase()),
70
+ scope: dep.scope,
71
+ ecosystem: "pypi",
72
+ sourceManifest: relativeManifest,
73
+ ...license !== void 0 ? { license } : {}
74
+ });
75
+ }
76
+ }
77
+ }
78
+ const pdmDeps = extractPdmDependencies(content, relativeManifest);
79
+ for (const dep of pdmDeps) {
80
+ if (!dependencies.find((d) => d.name === dep.name)) {
81
+ dependencies.push({
82
+ name: dep.name,
83
+ declaredConstraint: dep.constraint,
84
+ resolvedVersion: resolvedVersions.get(dep.name.toLowerCase()),
85
+ scope: dep.scope,
86
+ ecosystem: "pypi",
87
+ sourceManifest: relativeManifest,
88
+ ...license !== void 0 ? { license } : {}
89
+ });
90
+ }
91
+ }
92
+ return dependencies;
93
+ }
94
+ function extractPep621Dependencies(content, relativeManifest) {
95
+ const deps = [];
96
+ const depsBlock = extractTomlArray(content, /^\[project\]/m, "dependencies");
97
+ for (const spec of depsBlock) {
98
+ const dep = parsePep508Spec(spec, relativeManifest);
99
+ if (dep) deps.push({ ...dep, scope: "production" });
100
+ }
101
+ const optSection = extractSection(content, /^\[project\.optional-dependencies\]/m);
102
+ if (optSection) {
103
+ for (const m of optSection.matchAll(/^\s*([a-zA-Z0-9_-]+)\s*=\s*\[([^\]]*)\]/gm)) {
104
+ const groupName = m[1].toLowerCase();
105
+ const isDevGroup = /^(dev|test|lint|docs|ci|build|check|debug)/.test(groupName);
106
+ const items = parseTomlStringArray(m[2]);
107
+ for (const spec of items) {
108
+ const dep = parsePep508Spec(spec, relativeManifest);
109
+ if (dep) deps.push({ ...dep, scope: isDevGroup ? "development" : "optional" });
110
+ }
111
+ }
112
+ }
113
+ return deps;
114
+ }
115
+ function hasPoetrySection(content) {
116
+ return /^\[tool\.poetry/m.test(content);
117
+ }
118
+ function extractPoetryDependencies(content, relativeManifest) {
119
+ const deps = [];
120
+ const sections = [
121
+ { pattern: /^\[tool\.poetry\.dependencies\]/m, scope: "production" },
122
+ { pattern: /^\[tool\.poetry\.dev-dependencies\]/m, scope: "development" }
123
+ ];
124
+ for (const m of content.matchAll(/^\[tool\.poetry\.group\.([a-zA-Z0-9_-]+)\.dependencies\]/gm)) {
125
+ const groupName = m[1].toLowerCase();
126
+ const scope = /^(dev|test|lint|docs|ci)/.test(groupName) ? "development" : "optional";
127
+ sections.push({ pattern: new RegExp(`^\\[tool\\.poetry\\.group\\.${m[1]}\\.dependencies\\]`, "m"), scope });
128
+ }
129
+ for (const { pattern, scope } of sections) {
130
+ const section = extractSection(content, pattern);
131
+ if (!section) continue;
132
+ for (const line of section.split("\n")) {
133
+ const trimmed = line.trim();
134
+ if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith("[")) break;
135
+ const simpleMatch = trimmed.match(/^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)\s*=\s*"([^"]+)"/);
136
+ if (simpleMatch) {
137
+ const name = simpleMatch[1];
138
+ if (name === "python") continue;
139
+ deps.push({ name: normalizePypiName(name), constraint: simpleMatch[3], scope });
140
+ continue;
141
+ }
142
+ const tableMatch = trimmed.match(/^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)\s*=\s*\{/);
143
+ if (tableMatch) {
144
+ const name = tableMatch[1];
145
+ if (name === "python") continue;
146
+ const versionMatch = trimmed.match(/version\s*=\s*"([^"]+)"/);
147
+ if (versionMatch) {
148
+ deps.push({ name: normalizePypiName(name), constraint: versionMatch[1], scope });
149
+ } else {
150
+ deps.push({ name: normalizePypiName(name), constraint: "*", scope });
151
+ }
152
+ }
153
+ }
154
+ }
155
+ return deps;
156
+ }
157
+ function extractPdmDependencies(content, relativeManifest) {
158
+ const deps = [];
159
+ const section = extractSection(content, /^\[tool\.pdm\.dev-dependencies\]/m);
160
+ if (section) {
161
+ for (const m of section.matchAll(/^\s*([a-zA-Z0-9_-]+)\s*=\s*\[([^\]]*)\]/gm)) {
162
+ const items = parseTomlStringArray(m[2]);
163
+ for (const spec of items) {
164
+ const dep = parsePep508Spec(spec, relativeManifest);
165
+ if (dep) deps.push({ ...dep, scope: "development" });
166
+ }
167
+ }
168
+ }
169
+ return deps;
170
+ }
171
+ function parsePep508Spec(spec, _relativeManifest) {
172
+ const withoutMarker = spec.split(";")[0].trim();
173
+ const withoutExtras = withoutMarker.replace(/\[[^\]]*\]/, "").trim();
174
+ const match = withoutExtras.match(/^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)\s*(.*)/);
175
+ if (!match) return null;
176
+ const name = normalizePypiName(match[1]);
177
+ const constraint = match[3].trim() || "*";
178
+ return { name, constraint };
179
+ }
180
+ function loadResolvedVersions(manifestDir) {
181
+ const map = /* @__PURE__ */ new Map();
182
+ const candidates = ["poetry.lock", "pdm.lock", "uv.lock"];
183
+ for (const lockFile of candidates) {
184
+ const lockPath = path.join(manifestDir, lockFile);
185
+ if (!fs.existsSync(lockPath)) continue;
186
+ try {
187
+ const content = fs.readFileSync(lockPath, "utf8");
188
+ if (lockFile === "poetry.lock") extractFromPoetryLock(content, map);
189
+ else extractFromPdmUvLock(content, map);
190
+ break;
191
+ } catch (err) {
192
+ (0, import_errors.logWarn)(`[sec:pyproject] Failed to parse ${lockFile}: ${err instanceof Error ? err.message : String(err)}`);
193
+ }
194
+ }
195
+ return map;
196
+ }
197
+ function extractFromPoetryLock(content, map) {
198
+ for (const m of content.matchAll(/\[\[package\]\][^[]*?name\s*=\s*"([^"]+)"[^[]*?version\s*=\s*"([^"]+)"/gs)) {
199
+ map.set(m[1].toLowerCase(), m[2]);
200
+ }
201
+ }
202
+ function extractFromPdmUvLock(content, map) {
203
+ for (const m of content.matchAll(/\[\[(?:package|distribution)\]\][^[]*?name\s*=\s*"([^"]+)"[^[]*?version\s*=\s*"([^"]+)"/gs)) {
204
+ map.set(m[1].toLowerCase(), m[2]);
205
+ }
206
+ }
207
+ function extractSection(content, headerPattern) {
208
+ const match = headerPattern.exec(content);
209
+ if (!match) return null;
210
+ const start = match.index + match[0].length;
211
+ const remaining = content.slice(start);
212
+ const nextSection = remaining.match(/^\[/m);
213
+ return nextSection ? remaining.slice(0, nextSection.index) : remaining;
214
+ }
215
+ function extractTomlArray(content, sectionPattern, key) {
216
+ const section = extractSection(content, sectionPattern);
217
+ if (!section) return [];
218
+ const keyPattern = new RegExp(`^${key}\\s*=\\s*\\[([^\\]]*(?:\\][^\\[\\]]*\\[)*[^\\]]*)\\]`, "ms");
219
+ const m = keyPattern.exec(section);
220
+ if (!m) return [];
221
+ return parseTomlStringArray(m[1]);
222
+ }
223
+ function parseTomlStringArray(body) {
224
+ const results = [];
225
+ for (const m of body.matchAll(/"([^"]+)"/g)) {
226
+ results.push(m[1].trim());
227
+ }
228
+ for (const m of body.matchAll(/'([^']+)'/g)) {
229
+ results.push(m[1].trim());
230
+ }
231
+ return results.filter(Boolean);
232
+ }
233
+ function normalizePypiName(name) {
234
+ return name.toLowerCase().replace(/[-_.]+/g, "-");
235
+ }
236
+ function extractPyprojectLicense(content) {
237
+ const pep621Section = extractSection(content, /^\[project\]/m);
238
+ if (pep621Section) {
239
+ const tableTextMatch = pep621Section.match(/^license\s*=\s*\{[^}]*text\s*=\s*["']([^"']+)["'][^}]*\}/m);
240
+ if (tableTextMatch && tableTextMatch[1].trim() !== "") {
241
+ return tableTextMatch[1].trim();
242
+ }
243
+ const stringMatch = pep621Section.match(/^license\s*=\s*["']([^"']+)["']/m);
244
+ if (stringMatch && stringMatch[1].trim() !== "") {
245
+ return stringMatch[1].trim();
246
+ }
247
+ }
248
+ const poetrySection = extractSection(content, /^\[tool\.poetry\]/m);
249
+ if (poetrySection) {
250
+ const poetryLicenseMatch = poetrySection.match(/^license\s*=\s*["']([^"']+)["']/m);
251
+ if (poetryLicenseMatch && poetryLicenseMatch[1].trim() !== "") {
252
+ return poetryLicenseMatch[1].trim();
253
+ }
254
+ }
255
+ return void 0;
256
+ }
257
+ // Annotate the CommonJS export names for ESM import in node:
258
+ 0 && (module.exports = {
259
+ parsePyprojectManifest
260
+ });
261
+ //# sourceMappingURL=pyproject.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/security/manifest/plugins/pyproject.ts"],
4
+ "sourcesContent": ["/**\n * pyproject.toml Version Extraction Plugin for KiroGraph-Sec\n *\n * Handles modern Python packaging: PEP 621 (standard), Poetry, Hatch, PDM, Flit.\n * pyproject.toml is the canonical manifest for virtually all Python projects\n * created after 2021 \u2014 requirements.txt is only used for pinned deployment deps.\n *\n * Supports:\n * - PEP 621 [project] dependencies = [\"package>=1.0\"]\n * - Poetry [tool.poetry.dependencies] { package = \"^1.0\" }\n * - PDM [tool.pdm.dev-dependencies] { dev = [\"package>=1.0\"] }\n * - Hatch [tool.hatch.envs.default.dependencies] = [\"package>=1.0\"]\n * Lock files: poetry.lock, pdm.lock, uv.lock (all share the same version extraction)\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ParsedDependency } from '../../types';\nimport { logWarn } from '../../../errors';\n\ntype ResolvedVersionMap = Map<string, string>;\n\n// \u2500\u2500 Entry point \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function parsePyprojectManifest(\n manifestPath: string,\n projectRoot: string,\n): Promise<ParsedDependency[]> {\n const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\\\/g, '/');\n\n let content: string;\n try {\n content = fs.readFileSync(manifestPath, 'utf8');\n } catch (err) {\n logWarn(`[sec:pyproject] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);\n return [];\n }\n\n const manifestDir = path.dirname(manifestPath);\n const resolvedVersions = loadResolvedVersions(manifestDir);\n const license = extractPyprojectLicense(content);\n const dependencies: ParsedDependency[] = [];\n\n // \u2500\u2500 PEP 621 [project] \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const pep621Deps = extractPep621Dependencies(content, relativeManifest);\n for (const dep of pep621Deps) {\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion: resolvedVersions.get(dep.name.toLowerCase()),\n scope: dep.scope,\n ecosystem: 'pypi',\n sourceManifest: relativeManifest,\n ...(license !== undefined ? { license } : {}),\n });\n }\n\n // \u2500\u2500 Poetry [tool.poetry.dependencies] \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (dependencies.length === 0 || hasPoetrySection(content)) {\n const poetryDeps = extractPoetryDependencies(content, relativeManifest);\n for (const dep of poetryDeps) {\n if (!dependencies.find(d => d.name === dep.name)) {\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion: resolvedVersions.get(dep.name.toLowerCase()),\n scope: dep.scope,\n ecosystem: 'pypi',\n sourceManifest: relativeManifest,\n ...(license !== undefined ? { license } : {}),\n });\n }\n }\n }\n\n // \u2500\u2500 PDM [tool.pdm.dev-dependencies] \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const pdmDeps = extractPdmDependencies(content, relativeManifest);\n for (const dep of pdmDeps) {\n if (!dependencies.find(d => d.name === dep.name)) {\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion: resolvedVersions.get(dep.name.toLowerCase()),\n scope: dep.scope,\n ecosystem: 'pypi',\n sourceManifest: relativeManifest,\n ...(license !== undefined ? { license } : {}),\n });\n }\n }\n\n return dependencies;\n}\n\n// \u2500\u2500 PEP 621 extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface RawDep { name: string; constraint: string; scope: ParsedDependency['scope'] }\n\nfunction extractPep621Dependencies(content: string, relativeManifest: string): RawDep[] {\n const deps: RawDep[] = [];\n\n // [project] dependencies = [\"package>=1.0\", ...]\n const depsBlock = extractTomlArray(content, /^\\[project\\]/m, 'dependencies');\n for (const spec of depsBlock) {\n const dep = parsePep508Spec(spec, relativeManifest);\n if (dep) deps.push({ ...dep, scope: 'production' });\n }\n\n // [project.optional-dependencies] group = [\"package>=1.0\", ...]\n const optSection = extractSection(content, /^\\[project\\.optional-dependencies\\]/m);\n if (optSection) {\n for (const m of optSection.matchAll(/^\\s*([a-zA-Z0-9_-]+)\\s*=\\s*\\[([^\\]]*)\\]/gm)) {\n const groupName = m[1].toLowerCase();\n const isDevGroup = /^(dev|test|lint|docs|ci|build|check|debug)/.test(groupName);\n const items = parseTomlStringArray(m[2]);\n for (const spec of items) {\n const dep = parsePep508Spec(spec, relativeManifest);\n if (dep) deps.push({ ...dep, scope: isDevGroup ? 'development' : 'optional' });\n }\n }\n }\n\n return deps;\n}\n\n// \u2500\u2500 Poetry extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasPoetrySection(content: string): boolean {\n return /^\\[tool\\.poetry/m.test(content);\n}\n\nfunction extractPoetryDependencies(content: string, relativeManifest: string): RawDep[] {\n const deps: RawDep[] = [];\n\n const sections: Array<{ pattern: RegExp; scope: ParsedDependency['scope'] }> = [\n { pattern: /^\\[tool\\.poetry\\.dependencies\\]/m, scope: 'production' },\n { pattern: /^\\[tool\\.poetry\\.dev-dependencies\\]/m, scope: 'development' },\n ];\n\n // Also handle [tool.poetry.group.*.dependencies]\n for (const m of content.matchAll(/^\\[tool\\.poetry\\.group\\.([a-zA-Z0-9_-]+)\\.dependencies\\]/gm)) {\n const groupName = m[1].toLowerCase();\n const scope: ParsedDependency['scope'] = /^(dev|test|lint|docs|ci)/.test(groupName) ? 'development' : 'optional';\n sections.push({ pattern: new RegExp(`^\\\\[tool\\\\.poetry\\\\.group\\\\.${m[1]}\\\\.dependencies\\\\]`, 'm'), scope });\n }\n\n for (const { pattern, scope } of sections) {\n const section = extractSection(content, pattern);\n if (!section) continue;\n\n for (const line of section.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '' || trimmed.startsWith('#') || trimmed.startsWith('[')) break;\n\n // name = \"^1.0\" or name = { version = \"^1.0\", ... }\n const simpleMatch = trimmed.match(/^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)\\s*=\\s*\"([^\"]+)\"/);\n if (simpleMatch) {\n const name = simpleMatch[1];\n if (name === 'python') continue; // skip python version constraint\n deps.push({ name: normalizePypiName(name), constraint: simpleMatch[3], scope });\n continue;\n }\n\n // name = { version = \"^1.0\", ... }\n const tableMatch = trimmed.match(/^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)\\s*=\\s*\\{/);\n if (tableMatch) {\n const name = tableMatch[1];\n if (name === 'python') continue;\n const versionMatch = trimmed.match(/version\\s*=\\s*\"([^\"]+)\"/);\n if (versionMatch) {\n deps.push({ name: normalizePypiName(name), constraint: versionMatch[1], scope });\n } else {\n // path/git dep without version \u2014 record with wildcard\n deps.push({ name: normalizePypiName(name), constraint: '*', scope });\n }\n }\n }\n }\n\n return deps;\n}\n\n// \u2500\u2500 PDM extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractPdmDependencies(content: string, relativeManifest: string): RawDep[] {\n const deps: RawDep[] = [];\n\n // [tool.pdm.dev-dependencies] groups with arrays\n const section = extractSection(content, /^\\[tool\\.pdm\\.dev-dependencies\\]/m);\n if (section) {\n for (const m of section.matchAll(/^\\s*([a-zA-Z0-9_-]+)\\s*=\\s*\\[([^\\]]*)\\]/gm)) {\n const items = parseTomlStringArray(m[2]);\n for (const spec of items) {\n const dep = parsePep508Spec(spec, relativeManifest);\n if (dep) deps.push({ ...dep, scope: 'development' });\n }\n }\n }\n\n return deps;\n}\n\n// \u2500\u2500 PEP 508 spec parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction parsePep508Spec(spec: string, _relativeManifest: string): { name: string; constraint: string } | null {\n // PEP 508: name [extras] [version_spec] [; marker]\n // Strip markers (semicolon and beyond), extras ([...])\n const withoutMarker = spec.split(';')[0].trim();\n const withoutExtras = withoutMarker.replace(/\\[[^\\]]*\\]/, '').trim();\n\n const match = withoutExtras.match(/^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)\\s*(.*)/);\n if (!match) return null;\n\n const name = normalizePypiName(match[1]);\n const constraint = match[3].trim() || '*';\n return { name, constraint };\n}\n\n// \u2500\u2500 Lock file loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction loadResolvedVersions(manifestDir: string): ResolvedVersionMap {\n const map: ResolvedVersionMap = new Map();\n\n // Try poetry.lock, pdm.lock, uv.lock in order\n const candidates = ['poetry.lock', 'pdm.lock', 'uv.lock'];\n for (const lockFile of candidates) {\n const lockPath = path.join(manifestDir, lockFile);\n if (!fs.existsSync(lockPath)) continue;\n try {\n const content = fs.readFileSync(lockPath, 'utf8');\n if (lockFile === 'poetry.lock') extractFromPoetryLock(content, map);\n else extractFromPdmUvLock(content, map);\n break; // only use the first lock file found\n } catch (err) {\n logWarn(`[sec:pyproject] Failed to parse ${lockFile}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return map;\n}\n\nfunction extractFromPoetryLock(content: string, map: ResolvedVersionMap): void {\n // [[package]] blocks with name and version fields\n for (const m of content.matchAll(/\\[\\[package\\]\\][^[]*?name\\s*=\\s*\"([^\"]+)\"[^[]*?version\\s*=\\s*\"([^\"]+)\"/gs)) {\n map.set(m[1].toLowerCase(), m[2]);\n }\n}\n\nfunction extractFromPdmUvLock(content: string, map: ResolvedVersionMap): void {\n // [[package]] or [[distribution]] blocks (pdm/uv use slightly different headers)\n for (const m of content.matchAll(/\\[\\[(?:package|distribution)\\]\\][^[]*?name\\s*=\\s*\"([^\"]+)\"[^[]*?version\\s*=\\s*\"([^\"]+)\"/gs)) {\n map.set(m[1].toLowerCase(), m[2]);\n }\n}\n\n// \u2500\u2500 TOML helpers (no library dependency) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Extract the content after a section header until the next header. */\nfunction extractSection(content: string, headerPattern: RegExp): string | null {\n const match = headerPattern.exec(content);\n if (!match) return null;\n const start = match.index + match[0].length;\n const remaining = content.slice(start);\n const nextSection = remaining.match(/^\\[/m);\n return nextSection ? remaining.slice(0, nextSection.index) : remaining;\n}\n\n/** Extract a TOML array value by key from a section. */\nfunction extractTomlArray(content: string, sectionPattern: RegExp, key: string): string[] {\n const section = extractSection(content, sectionPattern);\n if (!section) return [];\n\n // Match key = [\"...\", \"...\", ...] \u2014 may span multiple lines\n const keyPattern = new RegExp(`^${key}\\\\s*=\\\\s*\\\\[([^\\\\]]*(?:\\\\][^\\\\[\\\\]]*\\\\[)*[^\\\\]]*)\\\\]`, 'ms');\n const m = keyPattern.exec(section);\n if (!m) return [];\n return parseTomlStringArray(m[1]);\n}\n\n/** Parse a TOML string array body (contents inside [...]) into individual strings. */\nfunction parseTomlStringArray(body: string): string[] {\n const results: string[] = [];\n for (const m of body.matchAll(/\"([^\"]+)\"/g)) {\n results.push(m[1].trim());\n }\n for (const m of body.matchAll(/'([^']+)'/g)) {\n results.push(m[1].trim());\n }\n return results.filter(Boolean);\n}\n\n/** Normalize PyPI package name: lowercase, replace - and _ with - (canonical form). */\nfunction normalizePypiName(name: string): string {\n return name.toLowerCase().replace(/[-_.]+/g, '-');\n}\n\n/**\n * Extract the license from a pyproject.toml file.\n *\n * Handles:\n * - PEP 621 [project] license = {text = \"MIT\"} or license = \"MIT\"\n * - Poetry [tool.poetry] license = \"MIT\"\n */\nfunction extractPyprojectLicense(content: string): string | undefined {\n // PEP 621: license = {text = \"MIT\"} or license = {file = \"LICENSE\"}\n const pep621Section = extractSection(content, /^\\[project\\]/m);\n if (pep621Section) {\n // license = {text = \"MIT\"}\n const tableTextMatch = pep621Section.match(/^license\\s*=\\s*\\{[^}]*text\\s*=\\s*[\"']([^\"']+)[\"'][^}]*\\}/m);\n if (tableTextMatch && tableTextMatch[1].trim() !== '') {\n return tableTextMatch[1].trim();\n }\n // license = \"MIT\"\n const stringMatch = pep621Section.match(/^license\\s*=\\s*[\"']([^\"']+)[\"']/m);\n if (stringMatch && stringMatch[1].trim() !== '') {\n return stringMatch[1].trim();\n }\n }\n\n // Poetry: [tool.poetry] license = \"MIT\"\n const poetrySection = extractSection(content, /^\\[tool\\.poetry\\]/m);\n if (poetrySection) {\n const poetryLicenseMatch = poetrySection.match(/^license\\s*=\\s*[\"']([^\"']+)[\"']/m);\n if (poetryLicenseMatch && poetryLicenseMatch[1].trim() !== '') {\n return poetryLicenseMatch[1].trim();\n }\n }\n\n return undefined;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }