fritzkit 0.0.0-stage → 0.1.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 (328) hide show
  1. package/.claude-plugin/marketplace.json +12 -0
  2. package/.claude-plugin/plugin.json +13 -0
  3. package/CHANGELOG.md +8 -0
  4. package/LICENSE +21 -0
  5. package/README.md +429 -2
  6. package/dist/cli/commands/doctor.d.ts +4 -0
  7. package/dist/cli/commands/doctor.js +7 -0
  8. package/dist/cli/commands/doctor.js.map +1 -0
  9. package/dist/cli/commands/export.d.ts +17 -0
  10. package/dist/cli/commands/export.js +81 -0
  11. package/dist/cli/commands/export.js.map +1 -0
  12. package/dist/cli/commands/kicad.d.ts +10 -0
  13. package/dist/cli/commands/kicad.js +22 -0
  14. package/dist/cli/commands/kicad.js.map +1 -0
  15. package/dist/cli/commands/parts.d.ts +22 -0
  16. package/dist/cli/commands/parts.js +46 -0
  17. package/dist/cli/commands/parts.js.map +1 -0
  18. package/dist/cli/commands/prune.d.ts +14 -0
  19. package/dist/cli/commands/prune.js +67 -0
  20. package/dist/cli/commands/prune.js.map +1 -0
  21. package/dist/cli/commands/render.d.ts +24 -0
  22. package/dist/cli/commands/render.js +62 -0
  23. package/dist/cli/commands/render.js.map +1 -0
  24. package/dist/cli/commands/schema.d.ts +10 -0
  25. package/dist/cli/commands/schema.js +35 -0
  26. package/dist/cli/commands/schema.js.map +1 -0
  27. package/dist/cli/commands/ui.d.ts +14 -0
  28. package/dist/cli/commands/ui.js +67 -0
  29. package/dist/cli/commands/ui.js.map +1 -0
  30. package/dist/cli/commands/validate.d.ts +24 -0
  31. package/dist/cli/commands/validate.js +91 -0
  32. package/dist/cli/commands/validate.js.map +1 -0
  33. package/dist/cli/context.d.ts +81 -0
  34. package/dist/cli/context.js +139 -0
  35. package/dist/cli/context.js.map +1 -0
  36. package/dist/cli/main.d.ts +2 -0
  37. package/dist/cli/main.js +8 -0
  38. package/dist/cli/main.js.map +1 -0
  39. package/dist/cli/program.d.ts +21 -0
  40. package/dist/cli/program.js +158 -0
  41. package/dist/cli/program.js.map +1 -0
  42. package/dist/cli/raster.d.ts +4 -0
  43. package/dist/cli/raster.js +9 -0
  44. package/dist/cli/raster.js.map +1 -0
  45. package/dist/core/compile/breadboard-util.d.ts +12 -0
  46. package/dist/core/compile/breadboard-util.js +107 -0
  47. package/dist/core/compile/breadboard-util.js.map +1 -0
  48. package/dist/core/compile/breadboard.d.ts +60 -0
  49. package/dist/core/compile/breadboard.js +513 -0
  50. package/dist/core/compile/breadboard.js.map +1 -0
  51. package/dist/core/compile/fzp.d.ts +12 -0
  52. package/dist/core/compile/fzp.js +183 -0
  53. package/dist/core/compile/fzp.js.map +1 -0
  54. package/dist/core/compile/icon.d.ts +17 -0
  55. package/dist/core/compile/icon.js +27 -0
  56. package/dist/core/compile/icon.js.map +1 -0
  57. package/dist/core/compile/index.d.ts +4 -0
  58. package/dist/core/compile/index.js +62 -0
  59. package/dist/core/compile/index.js.map +1 -0
  60. package/dist/core/compile/pcb.d.ts +39 -0
  61. package/dist/core/compile/pcb.js +164 -0
  62. package/dist/core/compile/pcb.js.map +1 -0
  63. package/dist/core/compile/schematic.d.ts +69 -0
  64. package/dist/core/compile/schematic.js +240 -0
  65. package/dist/core/compile/schematic.js.map +1 -0
  66. package/dist/core/compile/style.d.ts +52 -0
  67. package/dist/core/compile/style.js +72 -0
  68. package/dist/core/compile/style.js.map +1 -0
  69. package/dist/core/compile/types.d.ts +50 -0
  70. package/dist/core/compile/types.js +15 -0
  71. package/dist/core/compile/types.js.map +1 -0
  72. package/dist/core/export/bin.d.ts +61 -0
  73. package/dist/core/export/bin.js +221 -0
  74. package/dist/core/export/bin.js.map +1 -0
  75. package/dist/core/export/fzpz.d.ts +37 -0
  76. package/dist/core/export/fzpz.js +121 -0
  77. package/dist/core/export/fzpz.js.map +1 -0
  78. package/dist/core/export/index.d.ts +5 -0
  79. package/dist/core/export/index.js +6 -0
  80. package/dist/core/export/index.js.map +1 -0
  81. package/dist/core/export/install.d.ts +77 -0
  82. package/dist/core/export/install.js +183 -0
  83. package/dist/core/export/install.js.map +1 -0
  84. package/dist/core/export/prune.d.ts +72 -0
  85. package/dist/core/export/prune.js +165 -0
  86. package/dist/core/export/prune.js.map +1 -0
  87. package/dist/core/fritzing.d.ts +22 -0
  88. package/dist/core/fritzing.js +77 -0
  89. package/dist/core/fritzing.js.map +1 -0
  90. package/dist/core/identity.d.ts +29 -0
  91. package/dist/core/identity.js +70 -0
  92. package/dist/core/identity.js.map +1 -0
  93. package/dist/core/image/bbox.d.ts +27 -0
  94. package/dist/core/image/bbox.js +24 -0
  95. package/dist/core/image/bbox.js.map +1 -0
  96. package/dist/core/image/index.d.ts +8 -0
  97. package/dist/core/image/index.js +9 -0
  98. package/dist/core/image/index.js.map +1 -0
  99. package/dist/core/image/key.d.ts +72 -0
  100. package/dist/core/image/key.js +317 -0
  101. package/dist/core/image/key.js.map +1 -0
  102. package/dist/core/image/prepare.d.ts +31 -0
  103. package/dist/core/image/prepare.js +98 -0
  104. package/dist/core/image/prepare.js.map +1 -0
  105. package/dist/core/image/remover.d.ts +17 -0
  106. package/dist/core/image/remover.js +51 -0
  107. package/dist/core/image/remover.js.map +1 -0
  108. package/dist/core/index.d.ts +16 -0
  109. package/dist/core/index.js +17 -0
  110. package/dist/core/index.js.map +1 -0
  111. package/dist/core/kicad/footprint.d.ts +104 -0
  112. package/dist/core/kicad/footprint.js +317 -0
  113. package/dist/core/kicad/footprint.js.map +1 -0
  114. package/dist/core/kicad/index.d.ts +25 -0
  115. package/dist/core/kicad/index.js +197 -0
  116. package/dist/core/kicad/index.js.map +1 -0
  117. package/dist/core/kicad/sexpr.d.ts +35 -0
  118. package/dist/core/kicad/sexpr.js +163 -0
  119. package/dist/core/kicad/sexpr.js.map +1 -0
  120. package/dist/core/resolve.d.ts +113 -0
  121. package/dist/core/resolve.js +301 -0
  122. package/dist/core/resolve.js.map +1 -0
  123. package/dist/core/schema/part.d.ts +995 -0
  124. package/dist/core/schema/part.js +278 -0
  125. package/dist/core/schema/part.js.map +1 -0
  126. package/dist/core/schema/part.schema.json +1122 -0
  127. package/dist/core/svg.d.ts +20 -0
  128. package/dist/core/svg.js +56 -0
  129. package/dist/core/svg.js.map +1 -0
  130. package/dist/core/units.d.ts +28 -0
  131. package/dist/core/units.js +42 -0
  132. package/dist/core/units.js.map +1 -0
  133. package/dist/core/validate/checker.d.ts +46 -0
  134. package/dist/core/validate/checker.js +142 -0
  135. package/dist/core/validate/checker.js.map +1 -0
  136. package/dist/core/validate/doctor.d.ts +25 -0
  137. package/dist/core/validate/doctor.js +156 -0
  138. package/dist/core/validate/doctor.js.map +1 -0
  139. package/dist/core/validate/explain.d.ts +10 -0
  140. package/dist/core/validate/explain.js +135 -0
  141. package/dist/core/validate/explain.js.map +1 -0
  142. package/dist/core/validate/index.d.ts +21 -0
  143. package/dist/core/validate/index.js +96 -0
  144. package/dist/core/validate/index.js.map +1 -0
  145. package/dist/core/validate/structural.d.ts +74 -0
  146. package/dist/core/validate/structural.js +664 -0
  147. package/dist/core/validate/structural.js.map +1 -0
  148. package/dist/core/workspace.d.ts +69 -0
  149. package/dist/core/workspace.js +213 -0
  150. package/dist/core/workspace.js.map +1 -0
  151. package/dist/mcp/jsonpatch.d.ts +30 -0
  152. package/dist/mcp/jsonpatch.js +145 -0
  153. package/dist/mcp/jsonpatch.js.map +1 -0
  154. package/dist/mcp/main.d.ts +2 -0
  155. package/dist/mcp/main.js +5 -0
  156. package/dist/mcp/main.js.map +1 -0
  157. package/dist/mcp/server.d.ts +28 -0
  158. package/dist/mcp/server.js +310 -0
  159. package/dist/mcp/server.js.map +1 -0
  160. package/dist/server/api.d.ts +72 -0
  161. package/dist/server/api.js +507 -0
  162. package/dist/server/api.js.map +1 -0
  163. package/dist/server/events.d.ts +28 -0
  164. package/dist/server/events.js +134 -0
  165. package/dist/server/events.js.map +1 -0
  166. package/dist/server/http.d.ts +36 -0
  167. package/dist/server/http.js +127 -0
  168. package/dist/server/http.js.map +1 -0
  169. package/dist/server/index.d.ts +65 -0
  170. package/dist/server/index.js +193 -0
  171. package/dist/server/index.js.map +1 -0
  172. package/dist/ui/assets/index-DLU8opyI.js +63 -0
  173. package/dist/ui/assets/index-GhUA-T3b.css +1 -0
  174. package/dist/ui/index.html +14 -0
  175. package/package.json +89 -4
  176. package/skills/fritzkit/SKILL.md +690 -0
  177. package/skills/fritzkit/reference/examples.md +275 -0
  178. package/skills/fritzkit/reference/part-json.md +333 -0
  179. package/skills/fritzkit/scripts/measure.py +197 -0
  180. package/tools/fzp-checker/.python-version +1 -0
  181. package/tools/fzp-checker/README.md +45 -0
  182. package/tools/fzp-checker/check_fzp.py +48 -0
  183. package/tools/fzp-checker/pyproject.toml +26 -0
  184. package/tools/fzp-checker/uv.lock +266 -0
  185. package/tools/fzp-checker/vendor/LICENSE.txt +8 -0
  186. package/tools/fzp-checker/vendor/UPSTREAM.md +25 -0
  187. package/tools/fzp-checker/vendor/fzp_checker.py +14 -0
  188. package/tools/fzp-checker/vendor/scripts/checks/__init__.py +26 -0
  189. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/__init__.cpython-313.pyc +0 -0
  190. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/check_missing_leg_ids.cpython-313.pyc +0 -0
  191. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/connector_numbering.cpython-313.pyc +0 -0
  192. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/fzp_checker_runner.cpython-313.pyc +0 -0
  193. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/fzp_checkers.cpython-313.pyc +0 -0
  194. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/fzp_svg_checkers.cpython-313.pyc +0 -0
  195. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/fzp_utils.cpython-313.pyc +0 -0
  196. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/svg_checkers.cpython-313.pyc +0 -0
  197. package/tools/fzp-checker/vendor/scripts/checks/__pycache__/svg_utils.cpython-313.pyc +0 -0
  198. package/tools/fzp-checker/vendor/scripts/checks/check_missing_leg_ids.py +44 -0
  199. package/tools/fzp-checker/vendor/scripts/checks/checkascii.py +27 -0
  200. package/tools/fzp-checker/vendor/scripts/checks/checkcase.py +156 -0
  201. package/tools/fzp-checker/vendor/scripts/checks/checkcopies.py +104 -0
  202. package/tools/fzp-checker/vendor/scripts/checks/connector_numbering.py +79 -0
  203. package/tools/fzp-checker/vendor/scripts/checks/connectors_misnumbered.py +228 -0
  204. package/tools/fzp-checker/vendor/scripts/checks/explain_errors.md +95 -0
  205. package/tools/fzp-checker/vendor/scripts/checks/fzp_checker_runner.py +717 -0
  206. package/tools/fzp-checker/vendor/scripts/checks/fzp_checkers.py +1069 -0
  207. package/tools/fzp-checker/vendor/scripts/checks/fzp_svg_checkers.py +62 -0
  208. package/tools/fzp-checker/vendor/scripts/checks/fzp_utils.py +222 -0
  209. package/tools/fzp-checker/vendor/scripts/checks/inspector_fc51.png +0 -0
  210. package/tools/fzp-checker/vendor/scripts/checks/invisibleconnectors.py +118 -0
  211. package/tools/fzp-checker/vendor/scripts/checks/nolayeridcheck.txt +758 -0
  212. package/tools/fzp-checker/vendor/scripts/checks/requirements.txt +3 -0
  213. package/tools/fzp-checker/vendor/scripts/checks/svg_checkers.py +953 -0
  214. package/tools/fzp-checker/vendor/scripts/checks/svg_utils.py +96 -0
  215. package/tools/fzp-checker/vendor/scripts/checks/test_checkers.py +839 -0
  216. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/author_missing.fzp.test +3 -0
  217. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/author_present.fzp.test +4 -0
  218. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/buses_missing_id.fzp.test +8 -0
  219. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/buses_missing_node_members.fzp.test +7 -0
  220. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/buses_present_valid.fzp.test +8 -0
  221. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_layers_missing_attributes.fzp.test +16 -0
  222. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_layers_present_valid.fzp.test +14 -0
  223. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_numbering_invalid.fzp.test +70 -0
  224. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_numbering_valid.fzp.test +70 -0
  225. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_refs_valid.fzp.test +53 -0
  226. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_mixed.fzp.test +11 -0
  227. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_silkscreen_nested.fzp.test +11 -0
  228. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_style_attr.fzp.test +11 -0
  229. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_white_stroke.fzp.test +11 -0
  230. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_wrong_color.fzp.test +11 -0
  231. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_inherited.fzp.test +11 -0
  232. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_legacy.fzp.test +12 -0
  233. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_nested_copper.fzp.test +12 -0
  234. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_none.fzp.test +11 -0
  235. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_standard.fzp.test +12 -0
  236. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_uppercase.fzp.test +11 -0
  237. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/css_connector.fzp.test +100 -0
  238. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/description_missing.fzp.test +3 -0
  239. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/description_present.fzp.test +4 -0
  240. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/duplicate_ids.fzp.test +27 -0
  241. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/family_property_missing.fzp.test +6 -0
  242. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/family_property_present_valid.fzp.test +6 -0
  243. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/font_size.fzp.test +46 -0
  244. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/fritzing_version_invalid_format.fzp.test +4 -0
  245. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/fritzing_version_missing.fzp.test +4 -0
  246. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/fritzing_version_present_valid.fzp.test +4 -0
  247. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/gorn_absent.fzp.test +15 -0
  248. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/gorn_present.fzp.test +15 -0
  249. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/hybrid_connectors.fzp.test +232 -0
  250. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/invalid_xml.fzp.test +12 -0
  251. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_ids_match.fzp.test +29 -0
  252. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_ids_mismatch.fzp.test +30 -0
  253. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_nesting_invalid.fzp.test +11 -0
  254. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_nesting_valid.fzp.test +11 -0
  255. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/matrix_transform.fzp.test +8 -0
  256. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/missing_connector_refs.fzp.test +63 -0
  257. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/missing_leg_ids.fzp.test +34 -0
  258. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_missing.fzp.test +4 -0
  259. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_non_alnum.fzp.test +4 -0
  260. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_present.fzp.test +4 -0
  261. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_special_chars_absent.fzp.test +4 -0
  262. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_special_chars_present.fzp.test +4 -0
  263. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_too_short.fzp.test +4 -0
  264. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/no_layer_invalid.fzp.test +19 -0
  265. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/no_layer_namedview.fzp.test +19 -0
  266. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/no_layer_valid.fzp.test +19 -0
  267. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/pcb_only.fzp.test +48 -0
  268. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/property_fields_missing_name.fzp.test +6 -0
  269. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/property_fields_missing_value.fzp.test +6 -0
  270. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/property_fields_present.fzp.test +6 -0
  271. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/required_tags_missing.fzp.test +3 -0
  272. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/required_tags_present.fzp.test +11 -0
  273. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/stroke_test.fzp.test +60 -0
  274. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/template_svgs.fzp.test +35 -0
  275. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/title_missing.fzp.test +3 -0
  276. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/title_present.fzp.test +4 -0
  277. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/unique_ids.fzp.test +27 -0
  278. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/unique_property_names_duplicates.fzp.test +7 -0
  279. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/unique_property_names_unique.fzp.test +7 -0
  280. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/valid_xml.fzp.test +249 -0
  281. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/version_invalid_format.fzp.test +4 -0
  282. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/version_missing.fzp.test +3 -0
  283. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/version_present_valid.fzp.test +4 -0
  284. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/views_missing.fzp.test +3 -0
  285. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/views_present.fzp.test +8 -0
  286. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/connector_refs_valid_breadboard.svg +7 -0
  287. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/duplicate_ids_breadboard.svg +13 -0
  288. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/gorn_absent_breadboard.svg +7 -0
  289. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/gorn_present_breadboard.svg +7 -0
  290. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/hybrid_connectors_breadboard.svg +102 -0
  291. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/layer_nesting_invalid.svg +13 -0
  292. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/layer_nesting_valid.svg +13 -0
  293. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/matrix_transform.svg +11 -0
  294. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/missing_connector_refs_breadboard.svg +8 -0
  295. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/missing_leg_ids_breadboard.svg +9 -0
  296. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/test_layer_ids_match_breadboard.svg +9 -0
  297. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/test_layer_ids_mismatch_breadboard.svg +9 -0
  298. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/unique_ids_breadboard.svg +13 -0
  299. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/hybrid_connectors_icon.svg +78 -0
  300. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/no_layer_invalid.svg +4 -0
  301. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/no_layer_namedview.svg +9 -0
  302. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/no_layer_valid.svg +7 -0
  303. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/plain_pcb.svg +10 -0
  304. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/connector_refs_valid_pcb.svg +10 -0
  305. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_mixed.svg +8 -0
  306. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_silkscreen_nested.svg +10 -0
  307. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_style_attr.svg +6 -0
  308. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_white_stroke.svg +6 -0
  309. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_wrong_color.svg +6 -0
  310. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_inherited.svg +7 -0
  311. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_legacy.svg +10 -0
  312. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_nested_copper.svg +9 -0
  313. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_none.svg +7 -0
  314. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_standard.svg +10 -0
  315. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_uppercase.svg +7 -0
  316. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/css_connector.svg +25 -0
  317. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/font_size.svg +54 -0
  318. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/hybrid_connectors_pcb.svg +35 -0
  319. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/missing_connector_refs_pcb.svg +14 -0
  320. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/pcb-arduino-shield.svg +25 -0
  321. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/stroke_test.svg +12 -0
  322. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/test_layer_ids_match_pcb.svg +12 -0
  323. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/test_layer_ids_mismatch_pcb.svg +12 -0
  324. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/connector_refs_valid_schematic.svg +7 -0
  325. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/hybrid_connectors_schematic.svg +59 -0
  326. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/missing_connector_refs_schematic.svg +8 -0
  327. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/test_layer_ids_match_schematic.svg +6 -0
  328. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/test_layer_ids_mismatch_schematic.svg +6 -0
@@ -0,0 +1,62 @@
1
+ from .fzp_checkers import FZPChecker
2
+ from .fzp_utils import FZPUtils
3
+ from lxml import etree
4
+ import os
5
+
6
+ class FZPMissingConnectorRefsChecker(FZPChecker):
7
+ def __init__(self, fzp_doc, svg_docs):
8
+ super().__init__(fzp_doc)
9
+ self.svg_docs = svg_docs
10
+
11
+ def check(self):
12
+ view_layers = {
13
+ 'pcbView': ['copper0', 'copper1'],
14
+ 'breadboardView': ['breadboard'],
15
+ 'schematicView': ['schematic']
16
+ }
17
+
18
+ for view_name, layers in view_layers.items():
19
+ svg_doc = self.svg_docs.get(view_name)
20
+ if not svg_doc:
21
+ continue
22
+
23
+ try:
24
+ connector_layers = {}
25
+ connector_nodes = {} # Store the actual nodes
26
+
27
+ # Find connectors in each layer for this view
28
+ for layer in layers:
29
+ layer_groups = svg_doc.xpath(f"//*[@id='{layer}']")
30
+ for group in layer_groups:
31
+ connectors = group.xpath(".//*[starts-with(@id, 'connector') and (contains(@id, 'pin') or contains(@id, 'pad'))]")
32
+ for connector in connectors:
33
+ connector_id = connector.get('id')
34
+ if not connector_id:
35
+ continue
36
+
37
+ if connector_id not in connector_layers:
38
+ connector_layers[connector_id] = set()
39
+ connector_nodes[connector_id] = connector # Store the node
40
+ connector_layers[connector_id].add(layer)
41
+
42
+ # Check FZP references for each connector's required layers
43
+ for connector_id, required_layers in connector_layers.items():
44
+ connector_num = connector_id.replace('connector', '').replace('pin', '').replace('pad', '')
45
+ connector_node = connector_nodes[connector_id]
46
+ for layer in required_layers:
47
+ refs = self.fzp_doc.xpath(f"//connector[@id='connector{connector_num}']/views/{view_name}/p[@layer='{layer}']")
48
+ if not refs:
49
+ self.add_error(f"Connector {connector_id} is in {layer} layer in SVG but not referenced in FZP {view_name}", node=connector_node)
50
+
51
+ except Exception as e:
52
+ self.add_error(f"Error processing {view_name} SVG: {str(e)}")
53
+
54
+ return self.get_result()
55
+
56
+ @staticmethod
57
+ def get_name():
58
+ return "missing_connector_refs"
59
+
60
+ @staticmethod
61
+ def get_description():
62
+ return "Check that all connectors in SVG layer groups are properly referenced in FZP"
@@ -0,0 +1,222 @@
1
+ import os
2
+ import re
3
+ import zipfile
4
+ import tempfile
5
+ import shutil
6
+
7
+ class FZPUtils:
8
+ @staticmethod
9
+ def get_svg_path(fzp_path, image, view_name):
10
+ dir_path = os.path.dirname(fzp_path)
11
+
12
+ # Check if this is an extracted fzpz structure (SVGs in same directory as FZP)
13
+ is_fzpz_structure = FZPUtils.is_fzpz_structure(fzp_path, image)
14
+
15
+ if is_fzpz_structure:
16
+ # For fzpz files, check for the dot-prefixed naming conventions
17
+ if '/' in image:
18
+ # Try pattern: icon/file.svg -> icon.file.svg
19
+ fzpz_filename = image.replace('/', '.')
20
+ svg_path = os.path.join(dir_path, fzpz_filename)
21
+ if os.path.isfile(svg_path):
22
+ # Skip template detection for fzpz files - process all SVGs
23
+ return svg_path
24
+
25
+ # Try pattern: icon/file.svg -> svg.icon.file.svg
26
+ fzpz_filename = 'svg.' + image.replace('/', '.')
27
+ svg_path = os.path.join(dir_path, fzpz_filename)
28
+ if os.path.isfile(svg_path):
29
+ # Skip template detection for fzpz files - process all SVGs
30
+ return svg_path
31
+
32
+ # Fall back to checking basename only
33
+ image_filename = os.path.basename(image)
34
+ svg_path = os.path.join(dir_path, image_filename)
35
+ if os.path.isfile(svg_path):
36
+ # Skip template detection for fzpz files - process all SVGs
37
+ return svg_path
38
+ else:
39
+ # Standard fritzing-parts structure
40
+ up_one_level = os.path.dirname(dir_path)
41
+
42
+ # Try contrib first (for imported parts), then core
43
+ svg_path_contrib = os.path.join(up_one_level, 'svg', 'contrib', image)
44
+ if os.path.isfile(svg_path_contrib):
45
+ # Contrib parts cannot be templates, so return the path directly
46
+ return svg_path_contrib
47
+ else:
48
+ # Fall back to core directory
49
+ svg_path = os.path.join(up_one_level, 'svg', 'core', image)
50
+ # Only check templates for core parts
51
+ if FZPUtils.is_template(svg_path, view_name):
52
+ return None # Skip template SVGs
53
+ return svg_path
54
+
55
+ @staticmethod
56
+ def is_template(svg_path, view):
57
+ # Extract the filename from the svg_path
58
+ filename = os.path.basename(svg_path)
59
+
60
+ # Initialize the flag to False
61
+ starts_with_prefix = False
62
+
63
+ if view == 'breadboardView':
64
+ # Check if filename starts with 'generic_ic_' or matches the 'generic_female_pin_header_' pattern
65
+ if filename.startswith('generic_ic_'):
66
+ starts_with_prefix = True
67
+ else:
68
+ # Define regex pattern for 'generic_female_pin_header_' filenames
69
+ pattern = r'^generic_female_pin_header_\d+_100mil_bread\.svg$'
70
+ starts_with_prefix = bool(re.match(pattern, filename))
71
+
72
+ elif view == 'iconView':
73
+ # For iconView, the filename should still start with 'generic_ic_'
74
+ starts_with_prefix = filename.startswith('generic_ic_')
75
+
76
+ elif view == 'schematicView':
77
+ # For schematicView, the filename should start with 'generic_'
78
+ starts_with_prefix = filename.startswith('generic_')
79
+
80
+ elif view == 'pcbView':
81
+ # For pcbView, check if the filename matches the 'dip_' or 'jumper_' pattern
82
+ dip_pattern = r'^dip_\d+_\d+mil_pcb\.svg$'
83
+ jumper_pattern = r'^jumper_\d+_\d+mil_pcb\.svg$'
84
+ starts_with_prefix = bool(re.match(dip_pattern, filename) or re.match(jumper_pattern, filename))
85
+
86
+ # Define valid views
87
+ valid_views = ['breadboardView', 'iconView', 'schematicView', 'pcbView']
88
+
89
+ # Check if the view is valid and if the filename starts with the correct prefix or matches the pattern
90
+ valid_view = view in valid_views
91
+ return starts_with_prefix and valid_view
92
+
93
+ @staticmethod
94
+ def is_fzpz_structure(fzp_path, image):
95
+ """
96
+ Check if this appears to be an extracted fzpz structure.
97
+ In fzpz files, SVGs are in the same directory as the FZP.
98
+ FZPZ files use a naming convention where subdirectory/file.svg becomes subdirectory.file.svg
99
+ """
100
+ dir_path = os.path.dirname(fzp_path)
101
+
102
+ # First check if the image file exists as-is (just the basename)
103
+ image_filename = os.path.basename(image)
104
+ svg_in_same_dir = os.path.isfile(os.path.join(dir_path, image_filename))
105
+
106
+ # If not found, check for the fzpz naming conventions:
107
+ # 1. subdirectory/file.svg becomes subdirectory.file.svg
108
+ # 2. subdirectory/file.svg becomes svg.subdirectory.file.svg
109
+ if not svg_in_same_dir and '/' in image:
110
+ # Try pattern: icon/file.svg -> icon.file.svg
111
+ fzpz_filename = image.replace('/', '.')
112
+ svg_in_same_dir = os.path.isfile(os.path.join(dir_path, fzpz_filename))
113
+
114
+ # Try pattern: icon/file.svg -> svg.icon.file.svg
115
+ if not svg_in_same_dir:
116
+ fzpz_filename = 'svg.' + image.replace('/', '.')
117
+ svg_in_same_dir = os.path.isfile(os.path.join(dir_path, fzpz_filename))
118
+
119
+ # Also check if we don't have the standard fritzing-parts directory structure
120
+ up_one_level = os.path.dirname(dir_path)
121
+ svg_in_standard_location = os.path.isfile(os.path.join(up_one_level, 'svg', 'core', image))
122
+
123
+ return svg_in_same_dir and not svg_in_standard_location
124
+
125
+ @staticmethod
126
+ def extract_fzpz(fzpz_path, extract_to=None):
127
+ """
128
+ Extract an fzpz file to a temporary or specified directory.
129
+ Returns the path to the extracted FZP file.
130
+ """
131
+ if not fzpz_path.endswith('.fzpz'):
132
+ raise ValueError("File must have .fzpz extension")
133
+
134
+ if not os.path.isfile(fzpz_path):
135
+ raise FileNotFoundError(f"FZPZ file not found: {fzpz_path}")
136
+
137
+ if extract_to is None:
138
+ extract_to = tempfile.mkdtemp()
139
+
140
+ try:
141
+ with zipfile.ZipFile(fzpz_path, 'r') as zip_file:
142
+ FZPUtils._validate_zip_paths(zip_file, fzpz_path)
143
+
144
+ zip_file.extractall(extract_to)
145
+
146
+ # Find the FZP file in the extracted contents
147
+ for filename in os.listdir(extract_to):
148
+ if filename.endswith('.fzp'):
149
+ return os.path.join(extract_to, filename)
150
+
151
+ raise ValueError("No FZP file found in FZPZ archive")
152
+
153
+ except zipfile.BadZipFile:
154
+ raise ValueError(f"Invalid FZPZ file: {fzpz_path}")
155
+
156
+ @staticmethod
157
+ def _validate_zip_paths(zip_file, fzpz_path):
158
+ """
159
+ Validate all paths in the zip file to prevent directory traversal attacks.
160
+ Raises ValueError if any unsafe paths are found.
161
+ """
162
+ unsafe_paths = []
163
+
164
+ for member in zip_file.infolist():
165
+ path = member.filename
166
+
167
+ # Check for absolute paths
168
+ if os.path.isabs(path):
169
+ unsafe_paths.append(f"Absolute path: {path}")
170
+ continue
171
+
172
+ # Check for directory traversal patterns
173
+ if ".." in path:
174
+ unsafe_paths.append(f"Directory traversal: {path}")
175
+ continue
176
+
177
+ # Normalize the path and check if it tries to escape the extraction directory
178
+ normalized_path = os.path.normpath(path)
179
+ if normalized_path.startswith("..") or os.path.isabs(normalized_path):
180
+ unsafe_paths.append(f"Path escape attempt: {path}")
181
+ continue
182
+
183
+ if unsafe_paths:
184
+ error_msg = f"Security violation in FZPZ file '{fzpz_path}': " + "; ".join(unsafe_paths)
185
+ raise ValueError(error_msg)
186
+
187
+ @staticmethod
188
+ def cleanup_extraction(extracted_dir):
189
+ """
190
+ Clean up extracted fzpz contents.
191
+ """
192
+ if os.path.exists(extracted_dir):
193
+ shutil.rmtree(extracted_dir)
194
+
195
+ @staticmethod
196
+ def get_svg_path_from_view(fzp_doc, fzp_path, view_name, layer=None):
197
+ views_section = fzp_doc.xpath("//views")[0]
198
+ for view in views_section:
199
+ if view.tag == view_name:
200
+ layers = view.xpath("layers")
201
+ if layers:
202
+ if layer:
203
+ layer_elements = layers[0].xpath("layer")
204
+ for layer_element in layer_elements:
205
+ if layer_element.attrib.get("layerId") == layer:
206
+ image = layers[0].attrib.get("image")
207
+ if image:
208
+ return FZPUtils.get_svg_path(fzp_path, image, view.tag)
209
+ else:
210
+ image = layers[0].attrib.get("image")
211
+ if image:
212
+ return FZPUtils.get_svg_path(fzp_path, image, view.tag)
213
+ return None
214
+
215
+
216
+ @staticmethod
217
+ def is_hybrid_or_unknown_layer(p_element):
218
+ layer = p_element.attrib.get("layer")
219
+ is_hybrid = p_element.attrib.get("hybrid") == "yes"
220
+ if not is_hybrid and layer == "unknown":
221
+ print(f"Unknown layer for regular connector in {p_element}.")
222
+ return layer == "unknown" or is_hybrid
@@ -0,0 +1,118 @@
1
+ import getopt
2
+ import sys
3
+ import os
4
+ import os.path
5
+ import re
6
+ import xml.dom.minidom
7
+ import xml.dom
8
+
9
+
10
+ def usage():
11
+ print("""
12
+ usage:
13
+ invisibleconnectors.py -d [svg folder]
14
+ invisibleconnectors.py -f [svg file]
15
+ Looks for connector-like svg elements with no fill or stroke.
16
+ Fritzing (at least version <= 1.0.3) can not colorize open connectors in red if the graphic doesn't have
17
+ a fill or stroke.
18
+ """)
19
+
20
+
21
+ def check_file(svgFilename):
22
+ try:
23
+ dom = xml.dom.minidom.parse(svgFilename)
24
+ except xml.parsers.expat.ExpatError as err:
25
+ print(str(err), svgFilename)
26
+ return
27
+
28
+ todo = [dom.documentElement]
29
+ while len(todo) > 0:
30
+ element = todo.pop(0)
31
+ for node in element.childNodes:
32
+ if node.nodeType == node.ELEMENT_NODE:
33
+ todo.append(node)
34
+
35
+ if not "connector" in element.getAttribute("id"):
36
+ continue
37
+ if "terminal" in element.getAttribute("id"):
38
+ continue
39
+
40
+ hasVisibleChild = False
41
+ for child in element.childNodes:
42
+ if child.nodeType == child.ELEMENT_NODE:
43
+ fill = child.getAttribute("fill")
44
+ if fill and fill != "none":
45
+ hasVisibleChild = True
46
+ break
47
+
48
+ if hasVisibleChild:
49
+ continue
50
+
51
+ stroke = element.getAttribute("stroke")
52
+ fill = element.getAttribute("fill")
53
+ strokewidth = element.getAttribute("stroke-width")
54
+
55
+ if len(stroke) == 0:
56
+ style = element.getAttribute("style")
57
+ if len(style) != 0:
58
+ style = style.replace(";", ":")
59
+ styles = style.split(":")
60
+ for index, name in enumerate(styles):
61
+ if name == "stroke":
62
+ stroke = styles[index + 1]
63
+ elif name == "stroke-width":
64
+ strokewidth = styles[index + 1]
65
+ elif name == "fill":
66
+ fill = styles[index + 1]
67
+
68
+ if len(fill) > 0 and fill != "none":
69
+ continue
70
+
71
+ if len(strokewidth) > 0 and strokewidth != "0":
72
+ continue
73
+
74
+ print("invisible connector", svgFilename, element.getAttribute("id"))
75
+
76
+ def main():
77
+ try:
78
+ opts, args = getopt.getopt(sys.argv[1:], "hd:f:", ["help", "directory", "file"])
79
+ except getopt.GetoptError as err:
80
+ # print help information and exit:
81
+ print(str(err)) # will print something like "option -a not recognized"
82
+ usage()
83
+ sys.exit(2)
84
+
85
+ dir = None
86
+ file = None
87
+
88
+ for o, a in opts:
89
+ # print o
90
+ # print a
91
+ if o in ("-d", "--directory"):
92
+ dir = a
93
+ elif o in ("-f", "--file"):
94
+ file = a
95
+ elif o in ("-h", "--help"):
96
+ usage()
97
+ sys.exit(2)
98
+ else:
99
+ assert False, "unhandled option"
100
+
101
+ if not dir and not file:
102
+ usage()
103
+ sys.exit(2)
104
+
105
+ if file:
106
+ check_file(file)
107
+ else:
108
+ for root, dirs, files in os.walk(dir, topdown=False):
109
+ for filename in files:
110
+ if not filename.endswith(".svg"):
111
+ continue
112
+
113
+ svgFilename = os.path.join(root, filename)
114
+ check_file(svgFilename)
115
+
116
+
117
+ if __name__ == "__main__":
118
+ main()