breadkit-lint 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 (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +54 -0
  5. data/SECURITY.md +5 -0
  6. data/config/default.yml +36 -0
  7. data/docs/rules/Electrical/DanglingWire.md +9 -0
  8. data/docs/rules/Electrical/FloatingPin.md +9 -0
  9. data/docs/rules/Electrical/MissingSeriesResistor.md +11 -0
  10. data/docs/rules/Electrical/NetLabelConflict.md +10 -0
  11. data/docs/rules/Electrical/NoCommonGround.md +10 -0
  12. data/docs/rules/Electrical/PowerPinUnconnected.md +9 -0
  13. data/docs/rules/Electrical/ReversePolarity.md +10 -0
  14. data/docs/rules/Electrical/ShortCircuit.md +9 -0
  15. data/docs/rules/Electrical/ShortedComponent.md +9 -0
  16. data/docs/rules/Electrical/SplitRail.md +10 -0
  17. data/docs/rules/Electrical/SupplyVoltageRange.md +10 -0
  18. data/docs/rules/Intent/ConnectionMismatch.md +9 -0
  19. data/docs/rules/Intent/UnknownNet.md +9 -0
  20. data/docs/rules/Layout/DuplicateRef.md +10 -0
  21. data/docs/rules/Layout/HoleConflict.md +10 -0
  22. data/docs/rules/Layout/InvalidHole.md +9 -0
  23. data/docs/rules/Layout/InvalidPlacement.md +9 -0
  24. data/docs/rules/Layout/NoFreeHole.md +7 -0
  25. data/docs/rules/Layout/PinsInSameStrip.md +9 -0
  26. data/docs/rules/Layout/SplitNetLabel.md +3 -0
  27. data/docs/rules/Layout/UnknownBoard.md +3 -0
  28. data/docs/rules/Layout/UnknownOption.md +5 -0
  29. data/docs/rules/Layout/UnknownPart.md +9 -0
  30. data/docs/rules/Layout/UnknownPin.md +9 -0
  31. data/docs/rules/Layout/UnknownTransistorModel.md +5 -0
  32. data/docs/rules/Layout/UnplacedPin.md +3 -0
  33. data/docs/rules/Style/WireColor.md +9 -0
  34. data/exe/bklint +5 -0
  35. data/lib/breadkit/lint/rules/electrical.rb +371 -0
  36. data/lib/breadkit/lint/rules/intent.rb +59 -0
  37. data/lib/breadkit/lint/rules/layout.rb +33 -0
  38. data/lib/breadkit/lint/rules/style.rb +43 -0
  39. data/lib/breadkit/lint/rules/support.rb +88 -0
  40. data/lib/breadkit/lint/rules.rb +205 -0
  41. data/lib/breadkit/lint/version.rb +7 -0
  42. data/lib/breadkit/lint.rb +476 -0
  43. data/locales/en.yml +28 -0
  44. data/locales/ja.yml +65 -0
  45. data/package-lock.json +1172 -0
  46. data/package.json +12 -0
  47. data/scripts/check_bad_examples.rb +37 -0
  48. data/sig/breadkit/lint.rbs +68 -0
  49. data/site/favicon.svg +7 -0
  50. data/site/index.html +95 -0
  51. data/site/styles.css +14 -0
  52. metadata +111 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5ae47ac3ae7217a2a82b7515f278ad803d0784545f85d469cac5bb5256a5d56a
4
+ data.tar.gz: 123c596bd7f50e9da23e73d90e4fb6ad2c4ed8d9fe88274ba519497eec420a75
5
+ SHA512:
6
+ metadata.gz: e7391a75a996a8068d8c9446c704d6ac6d13d3d44b3ce4adfc3a827ed4e7980868540baecb3c90a4839b06c287a05d3ac8d618e2af120ee784b88b9b02d31799
7
+ data.tar.gz: b87c6a614fdad6c4d9392fde335d48fe82db2f364e72237fe578aa571f72511335ec6ecde1c96a1ea10763640617a76809a18797cc00e6ad5ec6bebea903f7a1
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-09-27
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # breadkit-lint
2
+
3
+ Project site: https://breadkit.github.io/breadkit-lint/
4
+
5
+ `bklint` checks Breadkit DSL and IR files for layout, electrical, and wiring-intent problems. DSL files execute as Ruby code; inspect only trusted files. Use IR JSON for data-only input. Configuration `require` entries also execute Ruby code, so load only trusted configuration files.
6
+
7
+ Install `breadkit-lint` directly; RubyGems installs its compatible `breadkit` core dependency. Shared circuit examples are in the [breadkit repository](https://github.com/breadkit/breadkit/tree/main/examples).
8
+
9
+ ```sh
10
+ bklint circuit.bk.rb
11
+ bklint circuit.bk.rb --only Electrical/ShortCircuit
12
+ bklint circuit.bk.rb --format json --out lint.json
13
+ bklint circuit.bk.rb --format github
14
+ bklint circuit.bk.rb --format sarif --out lint.sarif
15
+ ```
16
+
17
+ ## Options
18
+
19
+ `bklint [options] [FILES...]` accepts `.bk.rb` and Breadkit IR `.json` inputs. Directory arguments are scanned recursively. With no files, it scans visible inputs under the current directory and skips `node_modules`. Each input uses the nearest ancestor `.bklint.yml` unless `--config` is specified.
20
+
21
+ | Option | Description |
22
+ | --- | --- |
23
+ | `-f, --format FORMAT` | `text` (default), `json`, `github`, or `sarif`. |
24
+ | `-o, --out PATH` | Write formatter output to a file. |
25
+ | `-c, --config PATH` | Load a `.bklint.yml` configuration. |
26
+ | `--fail-level LEVEL` | `error`, `warning` (default), or `info`. |
27
+ | `--only RULES` / `--except RULES` | Select or skip comma-separated rule IDs. |
28
+ | `--switch-states MODE` | Evaluate `none`, `single` (default), or `all` switch states. |
29
+ | `--list-rules` | List registered rules. |
30
+ | `--explain RULE` | Show rule guidance and an example. |
31
+ | `--locale LOCALE` | `ja` or `en` for rule descriptions, messages, and text summary. |
32
+
33
+ Exit status is `0` when no offense meets the fail level, `1` when one does, and `2` for invalid input, configuration, or command usage.
34
+
35
+ ## Configuration
36
+
37
+ ```yaml
38
+ inherit_from:
39
+ - ./shared/bklint.yml
40
+ use_parts:
41
+ - ./parts/*.yml
42
+
43
+ Electrical/FloatingPin:
44
+ Severity: error
45
+
46
+ Style/WireColor:
47
+ Enabled: true
48
+ PositiveColors: [red, orange]
49
+ GroundColors: [black, blue]
50
+ ```
51
+
52
+ All built-in rules and defaults are in [`config/default.yml`](config/default.yml). `.bklint.yml` can also set `AllRules.SwitchStates`, `AllRules.FailLevel`, `AllRules.Exclude`, `AllRules.NewRules` (`pending`, `enable`, or `disable`), `AllRules.RequireDisableReason`, and `require` custom rule files. DSL `lint_disable` declarations suppress a rule globally or for one named component, pin, or wire. Unknown rule IDs are errors; set `reason:` when `RequireDisableReason` is enabled.
53
+
54
+ Use `bklint --format json` with `bkrender --annotations` to display offense markers on a diagram. Rule guidance is in [`docs/rules`](docs/rules).
data/SECURITY.md ADDED
@@ -0,0 +1,5 @@
1
+ # Security policy
2
+
3
+ DSL files are executable Ruby. Do not process files from untrusted sources; use IR JSON for data-only input.
4
+
5
+ Please report suspected vulnerabilities privately through GitHub's Security Advisories feature. Do not include exploit details in a public issue.
@@ -0,0 +1,36 @@
1
+ AllRules:
2
+ SwitchStates: single
3
+ FailLevel: warning
4
+ NewRules: pending
5
+
6
+ Layout/InvalidHole: {Enabled: true, Severity: error}
7
+ Layout/UnknownBoard: {Enabled: true, Severity: error}
8
+ Layout/UnknownPart: {Enabled: true, Severity: error}
9
+ Layout/UnknownTransistorModel: {Enabled: true, Severity: warning}
10
+ Layout/UnknownPin: {Enabled: true, Severity: error}
11
+ Layout/UnknownOption: {Enabled: true, Severity: error}
12
+ Layout/UnplacedPin: {Enabled: true, Severity: error}
13
+ Layout/DuplicateRef: {Enabled: true, Severity: error}
14
+ Layout/InvalidPlacement: {Enabled: true, Severity: error}
15
+ Layout/HoleConflict: {Enabled: true, Severity: error}
16
+ Layout/NoFreeHole: {Enabled: true, Severity: error}
17
+ Layout/SplitNetLabel: {Enabled: true, Severity: error}
18
+ Layout/PinsInSameStrip: {Enabled: true, Severity: error}
19
+ Electrical/ShortCircuit: {Enabled: true, Severity: error}
20
+ Electrical/ShortedComponent: {Enabled: true, Severity: warning}
21
+ Electrical/FloatingPin: {Enabled: true, Severity: warning}
22
+ Electrical/DanglingWire: {Enabled: true, Severity: warning}
23
+ Electrical/SplitRail: {Enabled: true, Severity: warning}
24
+ Electrical/MissingSeriesResistor: {Enabled: true, Severity: error}
25
+ Electrical/ReversePolarity: {Enabled: true, Severity: error}
26
+ Electrical/PowerPinUnconnected: {Enabled: true, Severity: warning}
27
+ Electrical/SupplyVoltageRange: {Enabled: true, Severity: error}
28
+ Electrical/NoCommonGround: {Enabled: true, Severity: warning}
29
+ Electrical/NetLabelConflict: {Enabled: true, Severity: error}
30
+ Intent/ConnectionMismatch: {Enabled: true, Severity: error}
31
+ Intent/UnknownNet: {Enabled: true, Severity: error}
32
+ Style/WireColor:
33
+ Enabled: true
34
+ Severity: info
35
+ PositiveColors: [red, orange]
36
+ GroundColors: [black, blue, gray]
@@ -0,0 +1,9 @@
1
+ # Electrical/DanglingWire
2
+
3
+ At least one wire end is not connected to another component, supply, or wire on that strip.
4
+
5
+ ```ruby
6
+ wire "a1", "a10"
7
+ ```
8
+
9
+ Connect each end to its intended circuit node or remove the unused wire.
@@ -0,0 +1,9 @@
1
+ # Electrical/FloatingPin
2
+
3
+ A component pin has no external connection. A pin listed with `unused:` is intentionally ignored.
4
+
5
+ ```ruby
6
+ led :D1, anode: "b10", cathode: "b12" # neither pin is wired elsewhere
7
+ ```
8
+
9
+ Connect the pin to the intended net or mark a deliberately unused IC pin with `unused:`.
@@ -0,0 +1,11 @@
1
+ # Electrical/MissingSeriesResistor
2
+
3
+ An LED has a known unprotected path across a supply. This MVP check uses net reachability and is conservative about complex load branches.
4
+
5
+ ```ruby
6
+ led :D1, anode: "b10", cathode: "g12"
7
+ wire "a10", "B+"
8
+ wire "h12", "B-"
9
+ ```
10
+
11
+ Add a current-limiting resistor in series with the LED and verify its two pins land on distinct nets.
@@ -0,0 +1,10 @@
1
+ # Electrical/NetLabelConflict
2
+
3
+ One connected net has multiple distinct labels.
4
+
5
+ ```ruby
6
+ net :VCC, at: "B+1"
7
+ net :GND, at: "B+2"
8
+ ```
9
+
10
+ Check whether the labels or the wiring are wrong, then give the connected net one consistent name.
@@ -0,0 +1,10 @@
1
+ # Electrical/NoCommonGround
2
+
3
+ Multiple power supplies belong to disconnected supply-reference groups.
4
+
5
+ ```ruby
6
+ supply :A, voltage: 5, plus: "B+1", minus: "B-1"
7
+ supply :B, voltage: 3.3, plus: "T+1", minus: "T-1"
8
+ ```
9
+
10
+ Connect the grounds when the powered circuits exchange signals or current.
@@ -0,0 +1,9 @@
1
+ # Electrical/PowerPinUnconnected
2
+
3
+ A part pin marked `role: power` or `role: ground` does not reach the matching supply.
4
+
5
+ ```ruby
6
+ ic :U1, "NE555", at: "e20" # connect pins 8 and 1 to VCC and GND
7
+ ```
8
+
9
+ Connect each required power pin to the corresponding supply rail.
@@ -0,0 +1,10 @@
1
+ # Electrical/ReversePolarity
2
+
3
+ The positive pin of a polarized part is at a lower known potential than its negative pin.
4
+
5
+ ```ruby
6
+ led :D1, anode: "b10", cathode: "g12"
7
+ # Connect anode to GND and cathode to VCC.
8
+ ```
9
+
10
+ Swap the connections so the positive pin faces the higher potential.
@@ -0,0 +1,9 @@
1
+ # Electrical/ShortCircuit
2
+
3
+ Power constraints assign incompatible voltages to one connected net. The message includes a physical route when one is available.
4
+
5
+ ```ruby
6
+ wire "B+", "B-"
7
+ ```
8
+
9
+ Remove the shorting connection and review the reported holes and wires before powering the circuit.
@@ -0,0 +1,9 @@
1
+ # Electrical/ShortedComponent
2
+
3
+ A two-pin component's pins resolve to the same net, so current can bypass the component.
4
+
5
+ ```ruby
6
+ resistor :R1, "330", pins: %w[a4 e4]
7
+ ```
8
+
9
+ Move the pins to separate strips and verify the resulting net list.
@@ -0,0 +1,10 @@
1
+ # Electrical/SplitRail
2
+
3
+ A used segment of a split power rail has no known supply potential while another segment of that rail is powered.
4
+
5
+ ```ruby
6
+ board :full, split_rails: true
7
+ # Add a wire to B+30 while the supply is attached to B+1.
8
+ ```
9
+
10
+ Bridge the rail sections with a wire or attach a supply to each required segment.
@@ -0,0 +1,10 @@
1
+ # Electrical/SupplyVoltageRange
2
+
3
+ The known voltage difference between a part's power and ground pins is outside its declared `supply_range`.
4
+
5
+ ```ruby
6
+ supply :USB, voltage: 3.3, plus: "B+1", minus: "B-1"
7
+ ic :U1, "NE555", at: "e20" # NE555 requires at least 4.5 V
8
+ ```
9
+
10
+ Use a valid supply voltage or a part rated for the circuit voltage.
@@ -0,0 +1,9 @@
1
+ # Intent/ConnectionMismatch
2
+
3
+ Actual connectivity differs from a declared `connected`, `isolated`, or `net` expectation.
4
+
5
+ ```ruby
6
+ expect { connected "R1.1", "D1.anode" }
7
+ ```
8
+
9
+ Correct the wiring or update the expectation to match the intended circuit. `strict: true` also rejects extra pins on a declared net.
@@ -0,0 +1,9 @@
1
+ # Intent/UnknownNet
2
+
3
+ An expectation or label refers to a hole, pin, supply terminal, or net name that cannot be resolved.
4
+
5
+ ```ruby
6
+ expect { connected "U1.9", :VCC }
7
+ ```
8
+
9
+ Check the reference spelling and part definition. Pin references must use a declared pin number or name.
@@ -0,0 +1,10 @@
1
+ # Layout/DuplicateRef
2
+
3
+ Component references and wire IDs must be unique within a circuit.
4
+
5
+ ```ruby
6
+ resistor :R1, "330", pins: %w[a1 a3]
7
+ resistor :R1, "1k", pins: %w[a5 a7]
8
+ ```
9
+
10
+ Give each component and explicitly named wire a distinct identifier.
@@ -0,0 +1,10 @@
1
+ # Layout/HoleConflict
2
+
3
+ Only one component lead or supply terminal can occupy a physical hole.
4
+
5
+ ```ruby
6
+ resistor :R1, "330", pins: %w[a1 a3]
7
+ led :D1, anode: "a1", cathode: "a5"
8
+ ```
9
+
10
+ Move one lead to a different hole. Components may still share a conductive strip through separate holes.
@@ -0,0 +1,9 @@
1
+ # Layout/InvalidHole
2
+
3
+ The reference does not identify a hole on the selected board.
4
+
5
+ ```ruby
6
+ wire "k5", "a10" # k is not a breadboard row
7
+ ```
8
+
9
+ Use an existing terminal or rail hole, for example `wire "j5", "a10"`.
@@ -0,0 +1,9 @@
1
+ # Layout/InvalidPlacement
2
+
3
+ A DIP must straddle rows `e` and `f`; a fixed footprint must fit inside the board.
4
+
5
+ ```ruby
6
+ ic :U1, "NE555", at: "c20"
7
+ ```
8
+
9
+ Place pin 1 on row `e` or `f` and leave enough board space for the full footprint.
@@ -0,0 +1,7 @@
1
+ # Layout/NoFreeHole
2
+
3
+ Automatic rail or pin-strip selection found no unoccupied hole.
4
+
5
+ This can happen when many wire endpoints request the same crowded rail or strip.
6
+
7
+ Choose an explicit free hole, or move some connections to another strip.
@@ -0,0 +1,9 @@
1
+ # Layout/PinsInSameStrip
2
+
3
+ Two pins of the same component share a conductive strip, bypassing the component.
4
+
5
+ ```ruby
6
+ resistor :R1, "330", pins: %w[a4 e4]
7
+ ```
8
+
9
+ Place the leads in different strips, such as `a4` and `a5`.
@@ -0,0 +1,3 @@
1
+ # Layout/SplitNetLabel
2
+
3
+ The same net label appears on disconnected parts of the board. Connect those locations or use distinct names.
@@ -0,0 +1,3 @@
1
+ # Layout/UnknownBoard
2
+
3
+ The selected board definition cannot be loaded. Check the board name or the path supplied to `use_boards`.
@@ -0,0 +1,5 @@
1
+ # Layout/UnknownOption
2
+
3
+ Reports a component or offboard option that Breadkit does not recognize. The electrical and intent checks are skipped until the option is corrected.
4
+
5
+ Check the option spelling or define the attribute in the part definition.
@@ -0,0 +1,9 @@
1
+ # Layout/UnknownPart
2
+
3
+ The named part definition is not built in or loaded with `use_parts`.
4
+
5
+ ```ruby
6
+ ic :U1, "NE556X", at: "e20"
7
+ ```
8
+
9
+ Use a known part ID or add a YAML definition and load it before placing the part.
@@ -0,0 +1,9 @@
1
+ # Layout/UnknownPin
2
+
3
+ A wire, label, or expectation refers to a pin that the component definition does not contain.
4
+
5
+ ```ruby
6
+ wire "U1.9", "a10" # NE555 has only pins 1 through 8
7
+ ```
8
+
9
+ Check the part pin list and use its pin number or name.
@@ -0,0 +1,5 @@
1
+ # Layout/UnknownTransistorModel
2
+
3
+ Warns when a transistor model is not recognized. Breadkit uses a generic EBC pinout in this case, which may differ from the physical component.
4
+
5
+ Specify a known model or define the part with its actual pin order.
@@ -0,0 +1,3 @@
1
+ # Layout/UnplacedPin
2
+
3
+ One or more component pins have no board hole. Supply every required pin location or use a supported footprint placement.
@@ -0,0 +1,9 @@
1
+ # Style/WireColor
2
+
3
+ A wire attached to a known positive or ground net uses a color outside the configured convention. Defaults are red or orange for positive voltage, and black, blue, or gray for ground.
4
+
5
+ ```ruby
6
+ wire "a10", "B+", color: :blue
7
+ ```
8
+
9
+ Choose a conventional color or set `PositiveColors` / `GroundColors` in `.bklint.yml`.
data/exe/bklint ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "breadkit/lint"
5
+ exit Breadkit::Lint::CLI.new.run(ARGV)