fritzkit 0.0.0-stage → 0.1.1

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 (319) 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/check_missing_leg_ids.py +44 -0
  190. package/tools/fzp-checker/vendor/scripts/checks/checkascii.py +27 -0
  191. package/tools/fzp-checker/vendor/scripts/checks/checkcase.py +156 -0
  192. package/tools/fzp-checker/vendor/scripts/checks/checkcopies.py +104 -0
  193. package/tools/fzp-checker/vendor/scripts/checks/connector_numbering.py +79 -0
  194. package/tools/fzp-checker/vendor/scripts/checks/connectors_misnumbered.py +228 -0
  195. package/tools/fzp-checker/vendor/scripts/checks/explain_errors.md +95 -0
  196. package/tools/fzp-checker/vendor/scripts/checks/fzp_checker_runner.py +717 -0
  197. package/tools/fzp-checker/vendor/scripts/checks/fzp_checkers.py +1069 -0
  198. package/tools/fzp-checker/vendor/scripts/checks/fzp_svg_checkers.py +62 -0
  199. package/tools/fzp-checker/vendor/scripts/checks/fzp_utils.py +222 -0
  200. package/tools/fzp-checker/vendor/scripts/checks/inspector_fc51.png +0 -0
  201. package/tools/fzp-checker/vendor/scripts/checks/invisibleconnectors.py +118 -0
  202. package/tools/fzp-checker/vendor/scripts/checks/nolayeridcheck.txt +758 -0
  203. package/tools/fzp-checker/vendor/scripts/checks/requirements.txt +3 -0
  204. package/tools/fzp-checker/vendor/scripts/checks/svg_checkers.py +953 -0
  205. package/tools/fzp-checker/vendor/scripts/checks/svg_utils.py +96 -0
  206. package/tools/fzp-checker/vendor/scripts/checks/test_checkers.py +839 -0
  207. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/author_missing.fzp.test +3 -0
  208. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/author_present.fzp.test +4 -0
  209. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/buses_missing_id.fzp.test +8 -0
  210. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/buses_missing_node_members.fzp.test +7 -0
  211. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/buses_present_valid.fzp.test +8 -0
  212. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_layers_missing_attributes.fzp.test +16 -0
  213. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_layers_present_valid.fzp.test +14 -0
  214. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_numbering_invalid.fzp.test +70 -0
  215. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_numbering_valid.fzp.test +70 -0
  216. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/connector_refs_valid.fzp.test +53 -0
  217. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_mixed.fzp.test +11 -0
  218. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_silkscreen_nested.fzp.test +11 -0
  219. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_style_attr.fzp.test +11 -0
  220. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_white_stroke.fzp.test +11 -0
  221. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_invalid_wrong_color.fzp.test +11 -0
  222. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_inherited.fzp.test +11 -0
  223. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_legacy.fzp.test +12 -0
  224. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_nested_copper.fzp.test +12 -0
  225. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_none.fzp.test +11 -0
  226. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_standard.fzp.test +12 -0
  227. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/copper_color_valid_uppercase.fzp.test +11 -0
  228. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/css_connector.fzp.test +100 -0
  229. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/description_missing.fzp.test +3 -0
  230. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/description_present.fzp.test +4 -0
  231. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/duplicate_ids.fzp.test +27 -0
  232. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/family_property_missing.fzp.test +6 -0
  233. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/family_property_present_valid.fzp.test +6 -0
  234. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/font_size.fzp.test +46 -0
  235. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/fritzing_version_invalid_format.fzp.test +4 -0
  236. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/fritzing_version_missing.fzp.test +4 -0
  237. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/fritzing_version_present_valid.fzp.test +4 -0
  238. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/gorn_absent.fzp.test +15 -0
  239. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/gorn_present.fzp.test +15 -0
  240. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/hybrid_connectors.fzp.test +232 -0
  241. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/invalid_xml.fzp.test +12 -0
  242. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_ids_match.fzp.test +29 -0
  243. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_ids_mismatch.fzp.test +30 -0
  244. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_nesting_invalid.fzp.test +11 -0
  245. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/layer_nesting_valid.fzp.test +11 -0
  246. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/matrix_transform.fzp.test +8 -0
  247. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/missing_connector_refs.fzp.test +63 -0
  248. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/missing_leg_ids.fzp.test +34 -0
  249. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_missing.fzp.test +4 -0
  250. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_non_alnum.fzp.test +4 -0
  251. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_present.fzp.test +4 -0
  252. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_special_chars_absent.fzp.test +4 -0
  253. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_special_chars_present.fzp.test +4 -0
  254. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/module_id_too_short.fzp.test +4 -0
  255. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/no_layer_invalid.fzp.test +19 -0
  256. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/no_layer_namedview.fzp.test +19 -0
  257. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/no_layer_valid.fzp.test +19 -0
  258. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/pcb_only.fzp.test +48 -0
  259. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/property_fields_missing_name.fzp.test +6 -0
  260. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/property_fields_missing_value.fzp.test +6 -0
  261. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/property_fields_present.fzp.test +6 -0
  262. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/required_tags_missing.fzp.test +3 -0
  263. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/required_tags_present.fzp.test +11 -0
  264. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/stroke_test.fzp.test +60 -0
  265. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/template_svgs.fzp.test +35 -0
  266. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/title_missing.fzp.test +3 -0
  267. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/title_present.fzp.test +4 -0
  268. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/unique_ids.fzp.test +27 -0
  269. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/unique_property_names_duplicates.fzp.test +7 -0
  270. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/unique_property_names_unique.fzp.test +7 -0
  271. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/valid_xml.fzp.test +249 -0
  272. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/version_invalid_format.fzp.test +4 -0
  273. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/version_missing.fzp.test +3 -0
  274. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/version_present_valid.fzp.test +4 -0
  275. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/views_missing.fzp.test +3 -0
  276. package/tools/fzp-checker/vendor/scripts/checks/test_data/core/views_present.fzp.test +8 -0
  277. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/connector_refs_valid_breadboard.svg +7 -0
  278. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/duplicate_ids_breadboard.svg +13 -0
  279. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/gorn_absent_breadboard.svg +7 -0
  280. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/gorn_present_breadboard.svg +7 -0
  281. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/hybrid_connectors_breadboard.svg +102 -0
  282. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/layer_nesting_invalid.svg +13 -0
  283. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/layer_nesting_valid.svg +13 -0
  284. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/matrix_transform.svg +11 -0
  285. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/missing_connector_refs_breadboard.svg +8 -0
  286. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/missing_leg_ids_breadboard.svg +9 -0
  287. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/test_layer_ids_match_breadboard.svg +9 -0
  288. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/test_layer_ids_mismatch_breadboard.svg +9 -0
  289. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/breadboard/unique_ids_breadboard.svg +13 -0
  290. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/hybrid_connectors_icon.svg +78 -0
  291. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/no_layer_invalid.svg +4 -0
  292. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/no_layer_namedview.svg +9 -0
  293. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/no_layer_valid.svg +7 -0
  294. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/icon/plain_pcb.svg +10 -0
  295. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/connector_refs_valid_pcb.svg +10 -0
  296. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_mixed.svg +8 -0
  297. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_silkscreen_nested.svg +10 -0
  298. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_style_attr.svg +6 -0
  299. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_white_stroke.svg +6 -0
  300. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_invalid_wrong_color.svg +6 -0
  301. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_inherited.svg +7 -0
  302. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_legacy.svg +10 -0
  303. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_nested_copper.svg +9 -0
  304. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_none.svg +7 -0
  305. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_standard.svg +10 -0
  306. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/copper_color_valid_uppercase.svg +7 -0
  307. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/css_connector.svg +25 -0
  308. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/font_size.svg +54 -0
  309. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/hybrid_connectors_pcb.svg +35 -0
  310. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/missing_connector_refs_pcb.svg +14 -0
  311. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/pcb-arduino-shield.svg +25 -0
  312. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/stroke_test.svg +12 -0
  313. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/test_layer_ids_match_pcb.svg +12 -0
  314. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/pcb/test_layer_ids_mismatch_pcb.svg +12 -0
  315. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/connector_refs_valid_schematic.svg +7 -0
  316. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/hybrid_connectors_schematic.svg +59 -0
  317. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/missing_connector_refs_schematic.svg +8 -0
  318. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/test_layer_ids_match_schematic.svg +6 -0
  319. package/tools/fzp-checker/vendor/scripts/checks/test_data/svg/core/schematic/test_layer_ids_mismatch_schematic.svg +6 -0
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Fritzing bin files (.fzb), in particular the My Parts bin (my_parts.fzb).
3
+ *
4
+ * The edits are textual on purpose: Fritzing writes the bin with CRLF line endings, a
5
+ * 4-space indent and an odd `icon="Mine.png" >` root tag, and we keep every byte we do
6
+ * not need to touch. Instance shape (as Fritzing writes it in search.fzb):
7
+ *
8
+ * <instance moduleIdRef="<moduleId>" modelIndex="<int>" path="<fzp path>">
9
+ * <views/>
10
+ * </instance>
11
+ */
12
+ import { existsSync } from "node:fs";
13
+ import { copyFile, mkdir, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
14
+ import { basename, dirname, join } from "node:path";
15
+ /**
16
+ * The minimal My Parts bin, byte for byte what Fritzing 1.0.7 ships on a fresh profile
17
+ * (CRLF, no BOM, note the space before `>` in the module tag).
18
+ */
19
+ export const EMPTY_MY_PARTS_BIN = '<?xml version="1.0" encoding="UTF-8"?>\r\n' +
20
+ '<module fritzingVersion="0.4.3b.0.0" icon="Mine.png" >\r\n' +
21
+ " <title>My Parts</title>\r\n" +
22
+ " <instances></instances>\r\n" +
23
+ "</module>\r\n";
24
+ /** Lowest modelIndex handed out when the bin has no instances yet. */
25
+ export const FIRST_MODEL_INDEX = 100000;
26
+ /** How many `<bin>.bak-*` files to keep next to the bin. */
27
+ export const MAX_BIN_BACKUPS = 10;
28
+ const INSTANCE_SRC = String.raw `<instance\b[^>]*?(?:\/>|>[\s\S]*?<\/instance\s*>)`;
29
+ const ATTR_RE = /([A-Za-z_][\w.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
30
+ function unescapeXml(s) {
31
+ return s
32
+ .replace(/&lt;/g, "<")
33
+ .replace(/&gt;/g, ">")
34
+ .replace(/&quot;/g, '"')
35
+ .replace(/&apos;/g, "'")
36
+ .replace(/&amp;/g, "&");
37
+ }
38
+ function escapeXml(s) {
39
+ return s
40
+ .replace(/&/g, "&amp;")
41
+ .replace(/</g, "&lt;")
42
+ .replace(/>/g, "&gt;")
43
+ .replace(/"/g, "&quot;");
44
+ }
45
+ function instanceFromXml(instanceXml) {
46
+ const open = /^<instance\b([^>]*?)\/?>/.exec(instanceXml)?.[1] ?? "";
47
+ const a = {};
48
+ for (const m of open.matchAll(ATTR_RE)) {
49
+ a[m[1]] = unescapeXml(m[2] ?? m[3] ?? "");
50
+ }
51
+ return {
52
+ moduleIdRef: a.moduleIdRef ?? "",
53
+ modelIndex: Number.parseInt(a.modelIndex ?? "", 10),
54
+ path: a.path ?? "",
55
+ };
56
+ }
57
+ /** Parse the `<instance>` elements of a bin document (in file order). */
58
+ export function parseBinInstances(xml) {
59
+ return [...xml.matchAll(new RegExp(INSTANCE_SRC, "g"))].map((m) => instanceFromXml(m[0]));
60
+ }
61
+ /** Read a bin file; a missing or empty file yields the minimal My Parts document. */
62
+ export async function readBin(path) {
63
+ let xml = "";
64
+ if (existsSync(path))
65
+ xml = await readFile(path, "utf8");
66
+ if (xml.trim() === "")
67
+ xml = EMPTY_MY_PARTS_BIN;
68
+ return { xml, instances: parseBinInstances(xml) };
69
+ }
70
+ function eolOf(xml) {
71
+ return xml.includes("\r\n") ? "\r\n" : "\n";
72
+ }
73
+ /** Indent unit of the file: the leading whitespace of the first indented element line. */
74
+ function indentUnitOf(xml) {
75
+ return /\n([ \t]+)</.exec(xml)?.[1] ?? " ";
76
+ }
77
+ /** Next modelIndex: greater than every existing one, FIRST_MODEL_INDEX at minimum. */
78
+ export function nextModelIndex(xml) {
79
+ let max = FIRST_MODEL_INDEX - 1;
80
+ for (const i of parseBinInstances(xml)) {
81
+ if (Number.isFinite(i.modelIndex) && i.modelIndex > max)
82
+ max = i.modelIndex;
83
+ }
84
+ return max + 1;
85
+ }
86
+ /**
87
+ * The exact XML of one instance. The first line carries no indent (the caller places
88
+ * it); the following lines are indented with baseIndent (+ indentUnit for `<views/>`).
89
+ */
90
+ export function binInstanceXml(inst, indentUnit = " ", baseIndent = "", eol = "\r\n") {
91
+ return (`<instance moduleIdRef="${escapeXml(inst.moduleIdRef)}" modelIndex="${inst.modelIndex}" ` +
92
+ `path="${escapeXml(inst.path)}">${eol}` +
93
+ `${baseIndent}${indentUnit}<views/>${eol}` +
94
+ `${baseIndent}</instance>`);
95
+ }
96
+ /**
97
+ * Append an instance just before `</instances>`, keeping the file's line endings and
98
+ * indentation. Returns the xml unchanged when moduleIdRef is already present. A missing
99
+ * modelIndex becomes nextModelIndex(xml).
100
+ */
101
+ export function addBinInstance(xml, inst) {
102
+ if (xml.trim() === "")
103
+ xml = EMPTY_MY_PARTS_BIN;
104
+ if (parseBinInstances(xml).some((i) => i.moduleIdRef === inst.moduleIdRef))
105
+ return xml;
106
+ const eol = eolOf(xml);
107
+ const unit = indentUnitOf(xml);
108
+ const full = {
109
+ moduleIdRef: inst.moduleIdRef,
110
+ path: inst.path,
111
+ modelIndex: inst.modelIndex ?? nextModelIndex(xml),
112
+ };
113
+ const selfClosing = /([ \t]*)<instances\s*\/>/.exec(xml);
114
+ if (selfClosing) {
115
+ const outer = selfClosing[1] ?? "";
116
+ const inner = outer + unit;
117
+ const block = `${outer}<instances>${eol}${inner}${binInstanceXml(full, unit, inner, eol)}${eol}` +
118
+ `${outer}</instances>`;
119
+ return (xml.slice(0, selfClosing.index) + block + xml.slice(selfClosing.index + selfClosing[0].length));
120
+ }
121
+ const close = /<\/instances\s*>/.exec(xml);
122
+ if (!close)
123
+ throw new Error("bin file has no <instances> element");
124
+ const lineStart = xml.lastIndexOf("\n", close.index - 1) + 1;
125
+ const before = xml.slice(lineStart, close.index);
126
+ if (/^[ \t]*$/.test(before)) {
127
+ // `</instances>` on its own line: insert a new line above it.
128
+ const inner = before + unit;
129
+ const line = `${inner}${binInstanceXml(full, unit, inner, eol)}${eol}`;
130
+ return xml.slice(0, lineStart) + line + xml.slice(lineStart);
131
+ }
132
+ // Inline `<instances></instances>` (or content on the same line): break it open.
133
+ const outer = /^[ \t]*/.exec(before)?.[0] ?? "";
134
+ const inner = outer + unit;
135
+ const head = xml.slice(0, close.index).replace(/[ \t]+$/, "");
136
+ return (`${head}${eol}${inner}${binInstanceXml(full, unit, inner, eol)}${eol}${outer}` +
137
+ xml.slice(close.index));
138
+ }
139
+ /**
140
+ * Remove every instance for which predicate is true, together with its indentation and
141
+ * the line break before it. An instances element left holding only whitespace collapses
142
+ * to `<instances></instances>` (the shape of a fresh bin).
143
+ */
144
+ export function removeBinInstances(xml, predicate) {
145
+ let changed = false;
146
+ const re = new RegExp(String.raw `(?:\r?\n)?[ \t]*(` + INSTANCE_SRC + ")", "g");
147
+ const out = xml.replace(re, (whole, inst) => {
148
+ if (!predicate(instanceFromXml(inst)))
149
+ return whole;
150
+ changed = true;
151
+ return "";
152
+ });
153
+ if (!changed)
154
+ return xml;
155
+ return out.replace(/<instances>\s*<\/instances>/, "<instances></instances>");
156
+ }
157
+ function stamp(d) {
158
+ const p = (n) => String(n).padStart(2, "0");
159
+ return (`${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-` +
160
+ `${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`);
161
+ }
162
+ function escapeRe(s) {
163
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
164
+ }
165
+ /** Order backup names by timestamp, then by numeric clash suffix. */
166
+ function compareBackupNames(a, b) {
167
+ const key = (s) => {
168
+ const m = /\.bak-(\d{8}-\d{6})(?:-(\d+))?$/.exec(s);
169
+ return [m?.[1] ?? "", Number(m?.[2] ?? 0)];
170
+ };
171
+ const [ta, na] = key(a);
172
+ const [tb, nb] = key(b);
173
+ if (ta !== tb)
174
+ return ta < tb ? -1 : 1;
175
+ return na - nb;
176
+ }
177
+ /**
178
+ * Copy the bin to `<bin>.bak-YYYYMMDD-HHMMSS` (local time; `-N` suffix on a clash) and
179
+ * delete all but the MAX_BIN_BACKUPS newest backups. Returns undefined when there is no
180
+ * bin to back up yet.
181
+ */
182
+ export async function backupBin(binPath, now = () => new Date()) {
183
+ if (!existsSync(binPath))
184
+ return undefined;
185
+ const base = `${binPath}.bak-${stamp(now())}`;
186
+ let target = base;
187
+ for (let n = 1; existsSync(target); n++)
188
+ target = `${base}-${n}`;
189
+ await copyFile(binPath, target);
190
+ const dir = dirname(binPath);
191
+ const re = new RegExp(`^${escapeRe(basename(binPath))}\\.bak-\\d{8}-\\d{6}(-\\d+)?$`);
192
+ const backups = (await readdir(dir))
193
+ .filter((f) => re.test(f))
194
+ .sort((a, b) => compareBackupNames(b, a));
195
+ for (const old of backups.slice(MAX_BIN_BACKUPS))
196
+ await rm(join(dir, old), { force: true });
197
+ return target;
198
+ }
199
+ /** Write a file atomically: write `<path>.tmp-<pid>` next to it, then rename over it. */
200
+ export async function writeFileAtomic(path, data) {
201
+ await mkdir(dirname(path), { recursive: true });
202
+ const tmp = `${path}.tmp-${process.pid}`;
203
+ await writeFile(tmp, data);
204
+ try {
205
+ await rename(tmp, path);
206
+ }
207
+ catch (e) {
208
+ await rm(tmp, { force: true });
209
+ throw e;
210
+ }
211
+ }
212
+ /**
213
+ * Write new bin xml, backing the old file up first unless `backup` is false. Returns the
214
+ * backup path (undefined when no backup was taken or there was no old file).
215
+ */
216
+ export async function writeBin(binPath, xml, opts = {}) {
217
+ const bak = opts.backup === false ? undefined : await backupBin(binPath, opts.now);
218
+ await writeFileAtomic(binPath, xml);
219
+ return bak;
220
+ }
221
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../../src/core/export/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { CompiledPart, View } from "../compile/types.js";
2
+ export interface FzpzEntry {
3
+ name: string;
4
+ data: Uint8Array;
5
+ }
6
+ /**
7
+ * Entry mtime. fflate encodes DOS time from LOCAL date components, so build the date from
8
+ * local components too: every machine then writes 2026-01-01 00:00:00 whatever its zone.
9
+ * Built per call (not a module constant) so a TZ change inside the process cannot shift it.
10
+ */
11
+ export declare const fzpzMtime: () => Date;
12
+ export declare const FZPZ_LEVEL = 6;
13
+ /** Zip entries (in the given order) into .fzpz bytes. Throws on bad or duplicate names. */
14
+ export declare function buildFzpzBytes(entries: readonly FzpzEntry[]): Uint8Array;
15
+ /** Write a compiled part as a .fzpz (atomically); returns the absolute output path. */
16
+ export declare function writeFzpz(compiled: Pick<CompiledPart, "entries">, outPath: string): Promise<string>;
17
+ export interface FzpInfo {
18
+ moduleId: string;
19
+ family?: string;
20
+ variant?: string;
21
+ title?: string;
22
+ version?: string;
23
+ /** `<layers image="...">` per view, exactly as written in the fzp. */
24
+ images: Partial<Record<View, string>>;
25
+ }
26
+ export interface FzpzContents extends FzpInfo {
27
+ entries: FzpzEntry[];
28
+ /** Name of the fzp entry, e.g. part.<moduleId>.fzp. */
29
+ fzpEntry: string;
30
+ fzp: string;
31
+ }
32
+ /** Pull moduleId, family/variant properties, title, version and layer images from an fzp. */
33
+ export declare function parseFzpInfo(fzp: string): FzpInfo;
34
+ /** Read a .fzpz from disk: entries in archive order plus the parsed fzp. */
35
+ export declare function readFzpz(path: string): Promise<FzpzContents>;
36
+ /** Same as readFzpz, from bytes. */
37
+ export declare function parseFzpzBytes(bytes: Uint8Array): FzpzContents;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * .fzpz = a FLAT zip (no directories) holding `part.<moduleId>.fzp` plus one
3
+ * `svg.<view>.<base>_<view>.svg` per view (names from identity.fzpzEntryNames).
4
+ * Output is byte-deterministic: fixed compression level and a fixed entry mtime.
5
+ */
6
+ import { readFile } from "node:fs/promises";
7
+ import { resolve } from "node:path";
8
+ import { unzipSync, zipSync } from "fflate";
9
+ import { XMLParser } from "fast-xml-parser";
10
+ import { VIEWS } from "../compile/types.js";
11
+ import { writeFileAtomic } from "./bin.js";
12
+ /**
13
+ * Entry mtime. fflate encodes DOS time from LOCAL date components, so build the date from
14
+ * local components too: every machine then writes 2026-01-01 00:00:00 whatever its zone.
15
+ * Built per call (not a module constant) so a TZ change inside the process cannot shift it.
16
+ */
17
+ export const fzpzMtime = () => new Date(2026, 0, 1, 0, 0, 0);
18
+ export const FZPZ_LEVEL = 6;
19
+ /** Zip entries (in the given order) into .fzpz bytes. Throws on bad or duplicate names. */
20
+ export function buildFzpzBytes(entries) {
21
+ const files = {};
22
+ for (const e of entries) {
23
+ if (!e.name || /[/\\]/.test(e.name) || e.name === "." || e.name === "..") {
24
+ throw new Error(`invalid .fzpz entry name "${e.name}" (the archive must be flat)`);
25
+ }
26
+ if (Object.prototype.hasOwnProperty.call(files, e.name)) {
27
+ throw new Error(`duplicate .fzpz entry "${e.name}"`);
28
+ }
29
+ files[e.name] = [e.data, { level: FZPZ_LEVEL, mtime: fzpzMtime() }];
30
+ }
31
+ return zipSync(files);
32
+ }
33
+ /** Write a compiled part as a .fzpz (atomically); returns the absolute output path. */
34
+ export async function writeFzpz(compiled, outPath) {
35
+ const abs = resolve(outPath);
36
+ await writeFileAtomic(abs, buildFzpzBytes(compiled.entries));
37
+ return abs;
38
+ }
39
+ const parser = new XMLParser({
40
+ ignoreAttributes: false,
41
+ attributeNamePrefix: "@_",
42
+ parseTagValue: false,
43
+ parseAttributeValue: false,
44
+ isArray: (name) => name === "property" || name === "layers",
45
+ });
46
+ function text(v) {
47
+ if (v == null)
48
+ return undefined;
49
+ if (typeof v === "string" || typeof v === "number")
50
+ return String(v).trim();
51
+ if (typeof v === "object" && "#text" in v) {
52
+ return String(v["#text"]).trim();
53
+ }
54
+ return undefined;
55
+ }
56
+ /** Pull moduleId, family/variant properties, title, version and layer images from an fzp. */
57
+ export function parseFzpInfo(fzp) {
58
+ const doc = parser.parse(fzp);
59
+ const mod = doc.module;
60
+ const moduleId = mod?.["@_moduleId"];
61
+ if (!mod || typeof moduleId !== "string" || moduleId === "") {
62
+ throw new Error("fzp has no <module moduleId=...>");
63
+ }
64
+ const info = { moduleId, images: {} };
65
+ const props = mod.properties?.property;
66
+ for (const p of props ?? []) {
67
+ const name = String(p["@_name"] ?? "").toLowerCase();
68
+ const value = text(p);
69
+ if (name === "family" && value !== undefined)
70
+ info.family = value;
71
+ if (name === "variant" && value !== undefined)
72
+ info.variant = value;
73
+ }
74
+ const title = text(mod.title);
75
+ if (title !== undefined)
76
+ info.title = title;
77
+ const version = text(mod.version);
78
+ if (version !== undefined)
79
+ info.version = version;
80
+ const views = mod.views;
81
+ for (const view of VIEWS) {
82
+ const v = views?.[`${view}View`];
83
+ const layers = v?.layers;
84
+ const image = layers?.[0]?.["@_image"];
85
+ if (typeof image === "string")
86
+ info.images[view] = image;
87
+ }
88
+ return info;
89
+ }
90
+ /** Read a .fzpz from disk: entries in archive order plus the parsed fzp. */
91
+ export async function readFzpz(path) {
92
+ const bytes = new Uint8Array(await readFile(path));
93
+ try {
94
+ return parseFzpzBytes(bytes);
95
+ }
96
+ catch (e) {
97
+ throw new Error(`${path}: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
98
+ }
99
+ }
100
+ /** Same as readFzpz, from bytes. */
101
+ export function parseFzpzBytes(bytes) {
102
+ let files;
103
+ try {
104
+ files = unzipSync(bytes);
105
+ }
106
+ catch (e) {
107
+ const why = e instanceof Error ? e.message : String(e);
108
+ throw new Error(`not a .fzpz: the file is not a readable zip archive (${why})`, { cause: e });
109
+ }
110
+ const entries = Object.entries(files)
111
+ .filter(([name]) => !name.endsWith("/"))
112
+ .map(([name, data]) => ({ name, data }));
113
+ const fzpEntries = entries.filter((e) => /\.fzp$/i.test(e.name));
114
+ if (fzpEntries.length !== 1) {
115
+ throw new Error(`.fzpz must hold exactly one .fzp, found ${fzpEntries.length}`);
116
+ }
117
+ const fzpEntry = fzpEntries[0];
118
+ const fzp = new TextDecoder().decode(fzpEntry.data);
119
+ return { ...parseFzpInfo(fzp), entries, fzpEntry: fzpEntry.name, fzp };
120
+ }
121
+ //# sourceMappingURL=fzpz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fzpz.js","sourceRoot":"","sources":["../../../src/core/export/fzpz.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Export (.fzpz), install into Fritzing's user parts folder, and prune old versions. */
2
+ export * from "./bin.js";
3
+ export * from "./fzpz.js";
4
+ export * from "./install.js";
5
+ export * from "./prune.js";
@@ -0,0 +1,6 @@
1
+ /** Export (.fzpz), install into Fritzing's user parts folder, and prune old versions. */
2
+ export * from "./bin.js";
3
+ export * from "./fzpz.js";
4
+ export * from "./install.js";
5
+ export * from "./prune.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/export/index.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { type FritzingPaths } from "../fritzing.js";
2
+ import type { CompiledPart } from "../compile/types.js";
3
+ import { type FzpzEntry } from "./fzpz.js";
4
+ export declare class FritzingRunningError extends Error {
5
+ constructor(action?: string);
6
+ }
7
+ /**
8
+ * Throw unless moduleId is a safe single path segment (checked before any fs call). A
9
+ * trailing "." is refused because Windows strips it, so "x-12345678." would alias the
10
+ * folder "x-12345678".
11
+ */
12
+ export declare function assertSafeModuleId(moduleId: string): void;
13
+ /** Absolute dir of a part inside userPartsDir; throws if it would escape the folder. */
14
+ export declare function partDirFor(userPartsDir: string, moduleId: string): string;
15
+ export interface InstallLayout {
16
+ moduleId: string;
17
+ dir: string;
18
+ fzpPath: string;
19
+ /** zip entry name -> absolute install path */
20
+ files: Record<string, string>;
21
+ /** Entries Fritzing's own importer would not install either; they are not written. */
22
+ ignored: string[];
23
+ }
24
+ export declare function isSafeEntryName(name: string): boolean;
25
+ /**
26
+ * Pure: where every entry goes. The folder name is the moduleId read from the fzp
27
+ * content; entry names map `part.X.fzp` -> `X.fzp` and `svg.<view>.Y.svg` -> `<view>/Y.svg`.
28
+ * Rejects any entry name with a path separator, `..` or other unsafe characters (a sign
29
+ * of a hostile archive). Other entries (readme, unknown view) are listed in `ignored` and
30
+ * not written: Fritzing's importer (moveToPartsFolder) likewise only copies part.* and
31
+ * the svg.* files the fzp references, and silently skips the rest.
32
+ */
33
+ export declare function plannedInstallLayout(entries: readonly FzpzEntry[], paths: Pick<FritzingPaths, "userPartsDir">): InstallLayout;
34
+ /**
35
+ * The `path` attribute written into the bin instance. Default: the absolute installed
36
+ * fzp path with forward slashes, verified on Fritzing 1.0.7b to make the part appear in
37
+ * My Parts after a restart. (search.fzb/core.fzb use the bare file name for core parts.)
38
+ */
39
+ export declare function binInstancePath(fzpAbs: string, _moduleId: string): string;
40
+ export interface InstallOptions {
41
+ paths?: FritzingPaths;
42
+ /** Install even while Fritzing is running. */
43
+ force?: boolean;
44
+ /** Add an instance to my_parts.fzb so the part shows in My Parts (default true). */
45
+ updateBin?: boolean;
46
+ /** Back the bin up before writing it (default true). */
47
+ backupBin?: boolean;
48
+ /** Compute and report, write nothing. */
49
+ dryRun?: boolean;
50
+ /** Injected for tests; defaults to isFritzingRunning. */
51
+ isRunning?: () => Promise<boolean>;
52
+ /** Injected for tests (backup file timestamp). */
53
+ now?: () => Date;
54
+ /** Bin `path` attribute; defaults to binInstancePath. */
55
+ instancePath?: (fzpAbs: string, moduleId: string) => string;
56
+ }
57
+ export interface InstallResult {
58
+ moduleId: string;
59
+ installedDir: string;
60
+ /** Absolute paths of the files written (or that would be written on a dry run). */
61
+ files: string[];
62
+ binPath: string;
63
+ binBackupPath?: string;
64
+ /** True when the folder already held this moduleId's fzp (re-install). */
65
+ alreadyInstalled: boolean;
66
+ /** Whether the bin gained (or would gain) an instance; false with updateBin: false. */
67
+ binUpdated: boolean;
68
+ /** Set when nothing was written, with the reason (e.g. "dry run"). */
69
+ skipped?: string;
70
+ /** Archive entries that were not installed (see plannedInstallLayout). */
71
+ ignoredEntries: string[];
72
+ /** Human-readable notes, e.g. one per ignored entry. */
73
+ warnings: string[];
74
+ }
75
+ /** Input: a .fzpz path or anything carrying the flat entries (a CompiledPart). */
76
+ export type InstallSource = string | Pick<CompiledPart, "entries">;
77
+ export declare function installPart(source: InstallSource, opts?: InstallOptions): Promise<InstallResult>;