@willcgage/module-schematic 0.66.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.cjs +24 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -6
- package/dist/index.d.ts +24 -6
- package/dist/index.js +24 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
/**
|
|
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
|
|
@@ -789,9 +803,11 @@ interface EditorBranch {
|
|
|
789
803
|
* draws track to it; the plate is placed first, connected later). */
|
|
790
804
|
trackId?: string | null;
|
|
791
805
|
}
|
|
792
|
-
/** Endplate B
|
|
793
|
-
*
|
|
794
|
-
*
|
|
806
|
+
/** Endplate B's configuration — or `"none"`, meaning **the module has no far
|
|
807
|
+
* endplate**: an end of the line, a pocket, or a loop's pure turnback. On a
|
|
808
|
+
* loop, a standard endplate B instead makes the balloon an INTERCHANGE (a second
|
|
809
|
+
* route connects there, e.g. Seaford). A module presents one conforming face,
|
|
810
|
+
* or two, or more; the standard governs the faces it offers, not how many (#184). */
|
|
795
811
|
type EndplateBConfig = TrackConfig | "none";
|
|
796
812
|
interface EditorState {
|
|
797
813
|
lengthInches: number;
|
|
@@ -1667,8 +1683,10 @@ interface ModuleGeometryInput {
|
|
|
1667
1683
|
geometryType?: string | null;
|
|
1668
1684
|
geometryDegrees?: number | null;
|
|
1669
1685
|
geometryOffsetInches?: number | null;
|
|
1670
|
-
/** Axial endplate configs (A first, then B). Missing → single.
|
|
1671
|
-
|
|
1686
|
+
/** Axial endplate configs (A first, then B). Missing → single. `"none"` at B
|
|
1687
|
+
* means the module has no far endplate at all — an end of the line, a pocket,
|
|
1688
|
+
* or a turnback (#184). */
|
|
1689
|
+
endplateConfigs?: ("single" | "double" | "none" | null | undefined)[];
|
|
1672
1690
|
/** Branch endplates (from the schematic doc, #170), positioned along the
|
|
1673
1691
|
* mainline axis. */
|
|
1674
1692
|
branches?: {
|
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
|
-
/**
|
|
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
|
|
@@ -789,9 +803,11 @@ interface EditorBranch {
|
|
|
789
803
|
* draws track to it; the plate is placed first, connected later). */
|
|
790
804
|
trackId?: string | null;
|
|
791
805
|
}
|
|
792
|
-
/** Endplate B
|
|
793
|
-
*
|
|
794
|
-
*
|
|
806
|
+
/** Endplate B's configuration — or `"none"`, meaning **the module has no far
|
|
807
|
+
* endplate**: an end of the line, a pocket, or a loop's pure turnback. On a
|
|
808
|
+
* loop, a standard endplate B instead makes the balloon an INTERCHANGE (a second
|
|
809
|
+
* route connects there, e.g. Seaford). A module presents one conforming face,
|
|
810
|
+
* or two, or more; the standard governs the faces it offers, not how many (#184). */
|
|
795
811
|
type EndplateBConfig = TrackConfig | "none";
|
|
796
812
|
interface EditorState {
|
|
797
813
|
lengthInches: number;
|
|
@@ -1667,8 +1683,10 @@ interface ModuleGeometryInput {
|
|
|
1667
1683
|
geometryType?: string | null;
|
|
1668
1684
|
geometryDegrees?: number | null;
|
|
1669
1685
|
geometryOffsetInches?: number | null;
|
|
1670
|
-
/** Axial endplate configs (A first, then B). Missing → single.
|
|
1671
|
-
|
|
1686
|
+
/** Axial endplate configs (A first, then B). Missing → single. `"none"` at B
|
|
1687
|
+
* means the module has no far endplate at all — an end of the line, a pocket,
|
|
1688
|
+
* or a turnback (#184). */
|
|
1689
|
+
endplateConfigs?: ("single" | "double" | "none" | null | undefined)[];
|
|
1672
1690
|
/** Branch endplates (from the schematic doc, #170), positioned along the
|
|
1673
1691
|
* mainline axis. */
|
|
1674
1692
|
branches?: {
|
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
|
|
535
|
+
return doc.loop === true;
|
|
536
536
|
}
|
|
537
537
|
var MAIN_TRACK_ID = "main";
|
|
538
538
|
var MAIN2_TRACK_ID = "main2";
|
|
@@ -701,18 +701,20 @@ function stateToDoc(state, recordNumber) {
|
|
|
701
701
|
]
|
|
702
702
|
) : [
|
|
703
703
|
{ id: "A", label: "West", tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configA }] },
|
|
704
|
-
//
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
704
|
+
// ⚠️ `configB: "none"` means the module HAS NO FAR ENDPLATE, and
|
|
705
|
+
// that is not loop-only (#184). An *end of the line* or a *pocket*
|
|
706
|
+
// presents one conforming face and the track simply stops. The
|
|
707
|
+
// standard governs the ends a module offers for joining; it never
|
|
708
|
+
// required a module to offer two. This used to coerce "none" to
|
|
709
|
+
// "single" and emit a B regardless, so a single-ended module was
|
|
710
|
+
// impossible to author.
|
|
711
|
+
...state.configB !== "none" ? [
|
|
712
|
+
{
|
|
713
|
+
id: "B",
|
|
714
|
+
label: "East",
|
|
715
|
+
tracks: [{ trackId: MAIN_TRACK_ID, lane: 0, config: state.configB }]
|
|
716
|
+
}
|
|
717
|
+
] : []
|
|
716
718
|
],
|
|
717
719
|
// Branch endplates C, D, … — junction connections at pos, off one side
|
|
718
720
|
// (#170). A set can carry several (e.g. a second railroad through).
|
|
@@ -927,8 +929,14 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
927
929
|
loopReturn: loop && d.loopReturn === "main2" ? "main2" : "same",
|
|
928
930
|
mainsSwapped: d.mainsSwapped === true,
|
|
929
931
|
configA: configOf("A"),
|
|
930
|
-
//
|
|
931
|
-
|
|
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",
|
|
932
940
|
branches: branchEps.map((ep) => ({
|
|
933
941
|
label: ep.label ?? "Branch",
|
|
934
942
|
pos: sc(ep.at.pos),
|
|
@@ -1982,7 +1990,7 @@ function deriveEndplatePoses(geo) {
|
|
|
1982
1990
|
trackOffsets: offsetsFor(cfg(0), half)
|
|
1983
1991
|
})
|
|
1984
1992
|
);
|
|
1985
|
-
const noB = geo.geometryType === "dead_end" || geo.loop === true;
|
|
1993
|
+
const noB = geo.geometryType === "dead_end" || geo.loop === true || geo.endplateConfigs?.[1] === "none";
|
|
1986
1994
|
const end = sectionedEndPose({ sections: geo.sections });
|
|
1987
1995
|
if (!noB && end) {
|
|
1988
1996
|
poses.push(
|