Skip to content

Commit 517e9c2

Browse files
kubeclaude
andcommitted
Add back pre-2025-11-28 old format import support
Consolidated old format schema, types, and conversion into a single file (old-format.ts) and integrated it as a last-resort fallback in parseSDCPNFile, after versioned and legacy formats fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e31b652 commit 517e9c2

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

libs/@hashintel/petrinaut/src/file-format/import-sdcpn.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { SDCPN } from "../core/types/sdcpn";
2+
import { convertOldFormatToSDCPN, oldFormatFileSchema } from "./old-format";
23
import {
34
legacySdcpnFileSchema,
45
SDCPN_FILE_FORMAT_VERSION,
@@ -106,6 +107,17 @@ export const parseSDCPNFile = (data: unknown): ImportResult => {
106107
};
107108
}
108109

110+
// Try the pre-2025-11-28 old format (different field names)
111+
const oldFormat = oldFormatFileSchema.safeParse(data);
112+
if (oldFormat.success) {
113+
const converted = convertOldFormatToSDCPN(oldFormat.data);
114+
return {
115+
ok: true,
116+
sdcpn: converted,
117+
hadMissingPositions: false,
118+
};
119+
}
120+
109121
return {
110122
ok: false,
111123
error: `Invalid SDCPN file: ${legacy.error.issues.map((i) => i.message).join(", ")}`,
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* Support for the pre-2025-11-28 SDCPN file format.
3+
*
4+
* This format used different field names (e.g. `type` instead of `colorId`,
5+
* `differentialEquationCode` instead of `differentialEquationId`, `iconId`
6+
* instead of `iconSlug`) and included `id`/`title` inside the SDCPN definition.
7+
*
8+
* This module validates and converts old-format files into the current SDCPN shape.
9+
*/
10+
11+
import { z } from "zod";
12+
13+
import type { SDCPN } from "../core/types/sdcpn";
14+
15+
// -- Zod schema ---------------------------------------------------------------
16+
17+
const arcSchema = z.object({
18+
placeId: z.string(),
19+
weight: z.number(),
20+
});
21+
22+
const oldPlaceSchema = z.object({
23+
id: z.string(),
24+
name: z.string(),
25+
type: z.string().nullable(),
26+
dynamicsEnabled: z.boolean(),
27+
differentialEquationCode: z.object({ refId: z.string() }).nullable(),
28+
visualizerCode: z.string().optional(),
29+
x: z.number(),
30+
y: z.number(),
31+
width: z.number().optional(),
32+
height: z.number().optional(),
33+
});
34+
35+
const oldTransitionSchema = z.object({
36+
id: z.string(),
37+
name: z.string(),
38+
inputArcs: z.array(arcSchema),
39+
outputArcs: z.array(arcSchema),
40+
lambdaType: z.enum(["predicate", "stochastic"]),
41+
lambdaCode: z.string(),
42+
transitionKernelCode: z.string(),
43+
x: z.number(),
44+
y: z.number(),
45+
width: z.number().optional(),
46+
height: z.number().optional(),
47+
});
48+
49+
const oldColorElementSchema = z.object({
50+
id: z.string(),
51+
name: z.string(),
52+
type: z.enum(["real", "integer", "boolean"]),
53+
});
54+
55+
const oldColorSchema = z.object({
56+
id: z.string(),
57+
name: z.string(),
58+
iconId: z.string(),
59+
colorCode: z.string(),
60+
elements: z.array(oldColorElementSchema),
61+
});
62+
63+
const oldDifferentialEquationSchema = z.object({
64+
id: z.string(),
65+
name: z.string(),
66+
typeId: z.string(),
67+
code: z.string(),
68+
});
69+
70+
const parameterSchema = z.object({
71+
id: z.string(),
72+
name: z.string(),
73+
variableName: z.string(),
74+
type: z.enum(["real", "integer", "boolean"]),
75+
defaultValue: z.string(),
76+
});
77+
78+
export const oldFormatFileSchema = z.object({
79+
id: z.string(),
80+
title: z.string(),
81+
places: z.array(oldPlaceSchema),
82+
transitions: z.array(oldTransitionSchema),
83+
types: z.array(oldColorSchema).default([]),
84+
differentialEquations: z.array(oldDifferentialEquationSchema).default([]),
85+
parameters: z.array(parameterSchema).default([]),
86+
});
87+
88+
type OldFormatFile = z.infer<typeof oldFormatFileSchema>;
89+
90+
// -- Conversion ---------------------------------------------------------------
91+
92+
export const convertOldFormatToSDCPN = (
93+
old: OldFormatFile,
94+
): SDCPN & { title: string } => {
95+
return {
96+
title: old.title,
97+
places: old.places.map(
98+
({ width: _w, height: _h, type, differentialEquationCode, ...rest }) => ({
99+
...rest,
100+
colorId: type,
101+
differentialEquationId: differentialEquationCode?.refId ?? null,
102+
}),
103+
),
104+
transitions: old.transitions.map(
105+
({ width: _w, height: _h, ...rest }) => rest,
106+
),
107+
types: old.types.map((t) => ({
108+
id: t.id,
109+
name: t.name,
110+
iconSlug: t.iconId,
111+
displayColor: t.colorCode,
112+
elements: t.elements.map((e) => ({
113+
elementId: e.id,
114+
name: e.name,
115+
type: e.type,
116+
})),
117+
})),
118+
differentialEquations: old.differentialEquations.map((de) => ({
119+
id: de.id,
120+
name: de.name,
121+
colorId: de.typeId,
122+
code: de.code,
123+
})),
124+
parameters: old.parameters,
125+
};
126+
};

0 commit comments

Comments
 (0)