@willcgage/module-schematic 0.67.0 → 0.68.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.
package/dist/index.d.cts CHANGED
@@ -673,7 +673,21 @@ declare function checkEndplateWidth(input: {
673
673
  config?: TrackConfig | "none" | null;
674
674
  trackOffsetInches?: number | null;
675
675
  }): EndplateWidthIssue[];
676
- /** Whether a doc is a single-endplate turnback (explicit flag or one endplate). */
676
+ /**
677
+ * Whether a doc is a balloon loop — **the authored flag, and only that**.
678
+ *
679
+ * ⚠️ This used to ALSO infer a loop from `endplates.length === 1`, which was
680
+ * safe only while the sole way to have one endplate was to be a turnback. #184
681
+ * ended that: an *end of the line* or a *pocket* presents one conforming face
682
+ * too, so every single-ended module was silently classified as a loop — drawn
683
+ * with a bulb, its endplate A relabelled "Entry", and positions past the throat
684
+ * read as being inside a balloon that doesn't exist (#191).
685
+ *
686
+ * A loop is now only ever a loop because someone said so: the Loop checkbox and
687
+ * the return-loop generator both set `loop: true`. Checked before removing the
688
+ * inference — no stored doc relied on it (no module in the catalogue has one
689
+ * endplate without the flag, and none is `category:"loop"` or `dead_end`).
690
+ */
677
691
  declare function isLoopDoc(doc: ModuleSchematicDoc): boolean;
678
692
  declare const MAIN_TRACK_ID = "main";
679
693
  /** The second main on double-track modules — a real track entity so turnouts
package/dist/index.d.ts CHANGED
@@ -673,7 +673,21 @@ declare function checkEndplateWidth(input: {
673
673
  config?: TrackConfig | "none" | null;
674
674
  trackOffsetInches?: number | null;
675
675
  }): EndplateWidthIssue[];
676
- /** Whether a doc is a single-endplate turnback (explicit flag or one endplate). */
676
+ /**
677
+ * Whether a doc is a balloon loop — **the authored flag, and only that**.
678
+ *
679
+ * ⚠️ This used to ALSO infer a loop from `endplates.length === 1`, which was
680
+ * safe only while the sole way to have one endplate was to be a turnback. #184
681
+ * ended that: an *end of the line* or a *pocket* presents one conforming face
682
+ * too, so every single-ended module was silently classified as a loop — drawn
683
+ * with a bulb, its endplate A relabelled "Entry", and positions past the throat
684
+ * read as being inside a balloon that doesn't exist (#191).
685
+ *
686
+ * A loop is now only ever a loop because someone said so: the Loop checkbox and
687
+ * the return-loop generator both set `loop: true`. Checked before removing the
688
+ * inference — no stored doc relied on it (no module in the catalogue has one
689
+ * endplate without the flag, and none is `category:"loop"` or `dead_end`).
690
+ */
677
691
  declare function isLoopDoc(doc: ModuleSchematicDoc): boolean;
678
692
  declare const MAIN_TRACK_ID = "main";
679
693
  /** The second main on double-track modules — a real track entity so turnouts
package/dist/index.js CHANGED
@@ -532,7 +532,7 @@ function endplateWidthFor(widths, id) {
532
532
  return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
533
533
  }
534
534
  function isLoopDoc(doc) {
535
- return doc.loop === true || doc.endplates.length === 1;
535
+ return doc.loop === true;
536
536
  }
537
537
  var MAIN_TRACK_ID = "main";
538
538
  var MAIN2_TRACK_ID = "main2";
@@ -929,8 +929,14 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
929
929
  loopReturn: loop && d.loopReturn === "main2" ? "main2" : "same",
930
930
  mainsSwapped: d.mainsSwapped === true,
931
931
  configA: configOf("A"),
932
- // On a loop, a missing B means pure turnback; present = interchange loop.
933
- configB: loop && !hasB ? "none" : configOf("B"),
932
+ // NO ENDPLATE B ⇒ "none", whatever kind of module this is. On a loop that
933
+ // reads as a pure turnback (a present B makes it an interchange); on an end
934
+ // of the line or a pocket it simply means the module has one face (#184).
935
+ // ⚠️ This used to be `loop && !hasB`, so "none" only survived a round trip on
936
+ // a loop — which passed its test yesterday ONLY because a single-endplate
937
+ // module was still being misclassified as one (#191). The absence of the
938
+ // plate is the fact; why it's absent doesn't change what to read.
939
+ configB: hasB ? configOf("B") : "none",
934
940
  branches: branchEps.map((ep) => ({
935
941
  label: ep.label ?? "Branch",
936
942
  pos: sc(ep.at.pos),