@willcgage/module-schematic 0.49.4 → 0.49.6

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
@@ -668,7 +668,9 @@ declare const N_CAR_LENGTH_INCHES = 3.3;
668
668
  /** How many cars fit in a span, from its drawn length — the derived capacity a
669
669
  * siding or an industry spot holds (never typed). */
670
670
  declare function carCapacity(fromPos: number, toPos: number, carLengthInches?: number): number;
671
- /** Parse a jsonb value into a schematic doc, or null if it isn't one. */
671
+ /** Parse a jsonb value into a schematic doc, or null if it isn't one.
672
+ * EVERY read path goes through here (catalog, module page, my-modules, FD), so
673
+ * it's also where a stored doc gets healed — see healSelfDivergingTurnouts. */
672
674
  declare function asModuleSchematic(x: unknown): ModuleSchematicDoc | null;
673
675
  interface EditorTrack {
674
676
  id: string;
package/dist/index.d.ts CHANGED
@@ -668,7 +668,9 @@ declare const N_CAR_LENGTH_INCHES = 3.3;
668
668
  /** How many cars fit in a span, from its drawn length — the derived capacity a
669
669
  * siding or an industry spot holds (never typed). */
670
670
  declare function carCapacity(fromPos: number, toPos: number, carLengthInches?: number): number;
671
- /** Parse a jsonb value into a schematic doc, or null if it isn't one. */
671
+ /** Parse a jsonb value into a schematic doc, or null if it isn't one.
672
+ * EVERY read path goes through here (catalog, module page, my-modules, FD), so
673
+ * it's also where a stored doc gets healed — see healSelfDivergingTurnouts. */
672
674
  declare function asModuleSchematic(x: unknown): ModuleSchematicDoc | null;
673
675
  interface EditorTrack {
674
676
  id: string;
package/dist/index.js CHANGED
@@ -462,13 +462,15 @@ function moduleFootprint(input) {
462
462
  const authored = benchworkOutline(input);
463
463
  const offA = input.endplateTrackOffsets?.["A"] ?? 0;
464
464
  const offB = input.endplateTrackOffsets?.["B"] ?? 0;
465
- const sectionOutlines = sectionFootprints(input, {
465
+ const secs = input.sections ?? [];
466
+ const sectionsOwnShape = secs.length > 1 || secs.some((s) => (s.outline?.length ?? 0) >= 3);
467
+ const sectionOutlines = sectionsOwnShape ? sectionFootprints(input, {
466
468
  centerline,
467
469
  widthA,
468
470
  widthB,
469
471
  offsetA: offA,
470
472
  offsetB: offB
471
- });
473
+ }) : [];
472
474
  return {
473
475
  centerline,
474
476
  band: benchworkBand(centerline, widthA, widthB, offA, offB),
@@ -537,12 +539,23 @@ function carCapacity(fromPos, toPos, carLengthInches = N_CAR_LENGTH_INCHES) {
537
539
  if (!(carLengthInches > 0)) return 0;
538
540
  return Math.max(0, Math.floor(Math.abs(toPos - fromPos) / carLengthInches));
539
541
  }
542
+ function healSelfDivergingTurnouts(turnouts) {
543
+ if (!turnouts?.some((t) => t.onTrack === t.divergeTrack)) return turnouts;
544
+ return turnouts.map((t) => {
545
+ if (t.onTrack !== t.divergeTrack) return t;
546
+ if (t.onTrack === MAIN_TRACK_ID) return { ...t, divergeTrack: MAIN2_TRACK_ID };
547
+ if (t.onTrack === MAIN2_TRACK_ID) return { ...t, divergeTrack: MAIN_TRACK_ID };
548
+ return t;
549
+ });
550
+ }
540
551
  function asModuleSchematic(x) {
541
552
  if (!x || typeof x !== "object") return null;
542
553
  const d = x;
543
554
  if (typeof d.version !== "number") return null;
544
555
  if (!Array.isArray(d.endplates) || !Array.isArray(d.tracks)) return null;
545
- return d;
556
+ const doc = d;
557
+ const healed = healSelfDivergingTurnouts(doc.turnouts);
558
+ return healed === doc.turnouts ? doc : { ...doc, turnouts: healed };
546
559
  }
547
560
  function emptyEditorState(lengthInches) {
548
561
  return {
@@ -931,24 +944,19 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
931
944
  trackB: x.tracks?.[1] ?? MAIN_TRACK_ID
932
945
  })),
933
946
  extraTracks,
934
- turnouts: (d.turnouts ?? []).map((t) => {
935
- let divergeTrack = t.divergeTrack;
936
- if (divergeTrack === t.onTrack) {
937
- if (t.onTrack === MAIN_TRACK_ID) divergeTrack = MAIN2_TRACK_ID;
938
- else if (t.onTrack === MAIN2_TRACK_ID) divergeTrack = MAIN_TRACK_ID;
939
- }
940
- return {
941
- id: t.id,
942
- name: t.name ?? "",
943
- pos: sc(t.pos),
944
- onTrack: t.onTrack,
945
- divergeTrack,
946
- kind: t.kind ?? "right",
947
- ...t.size ? { size: t.size } : {},
948
- ...t.curved ? { curved: true } : {},
949
- ...t.flipped ? { flipped: true } : {}
950
- };
951
- }),
947
+ // Heal a turnout that diverges into the track it sits on (#172) with the
948
+ // same helper the read path uses, so the editor and every renderer agree.
949
+ turnouts: (healSelfDivergingTurnouts(d.turnouts) ?? []).map((t) => ({
950
+ id: t.id,
951
+ name: t.name ?? "",
952
+ pos: sc(t.pos),
953
+ onTrack: t.onTrack,
954
+ divergeTrack: t.divergeTrack,
955
+ kind: t.kind ?? "right",
956
+ ...t.size ? { size: t.size } : {},
957
+ ...t.curved ? { curved: true } : {},
958
+ ...t.flipped ? { flipped: true } : {}
959
+ })),
952
960
  controlPoints: readControlPoints(d, sc),
953
961
  industries: (d.industries ?? []).map((ind) => ({
954
962
  id: ind.id,