@tsplc/config 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +6 -2
- package/dist/build.js +472 -0
- package/dist/build.js.map +13 -0
- package/dist/index.js +574 -0
- package/dist/index.js.map +13 -0
- package/dist/schema.js +554 -0
- package/dist/schema.js.map +12 -0
- package/package.json +51 -4
- package/src/build-schema.ts +245 -0
- package/src/build.ts +80 -0
- package/src/compiler.ts +168 -0
- package/src/index.ts +2 -0
- package/src/loader.ts +20 -0
- package/src/schema.ts +408 -0
- package/templates/README.md +17 -0
- package/templates/default.project +0 -0
- package/templates/provenance.json +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tsPLC contributors
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tsplc/config
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Part of [tsPLC](https://github.com/livingforjesus/tsplc).
|
|
4
|
+
|
|
5
|
+
The shared `tsplc.config.ts` schema: `defineConfig`, tasks, build and Docker settings, hardware devices, IO bindings, library dependencies, typegen and monitor options. Every tsPLC package and the editor read the same file.
|
|
6
|
+
|
|
7
|
+
See the [documentation](https://github.com/livingforjesus/tsplc/tree/main/docs). MIT licensed.
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
var __esm = (fn, res, err) => () => {
|
|
2
|
+
if (fn)
|
|
3
|
+
try {
|
|
4
|
+
res = fn(fn = 0);
|
|
5
|
+
} catch (e) {
|
|
6
|
+
err = [e];
|
|
7
|
+
}
|
|
8
|
+
if (err)
|
|
9
|
+
throw err[0];
|
|
10
|
+
return res;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// packages/config/src/build-schema.ts
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
var commandArgumentSchema, codesysTimeouts, positiveMilliseconds, pathSchema, wineSchema, localCodesysSchema, dockerImage = "tsplc-build:latest", containerCodesys, iecName, cyclicTasksSchema, ioBindingOptions, directIoBindingSchema, ethernetSchema, processImageSchema, deviceTreeSchema, controllerSchema, controllerTargetSchema, configSchema;
|
|
16
|
+
var init_build_schema = __esm(() => {
|
|
17
|
+
commandArgumentSchema = z.string().refine((value) => value.trim().length > 0, "Command arguments must not be empty").refine((value) => !/["\r\n\0]/.test(value), "Command arguments must not contain quotes, line breaks, or null bytes");
|
|
18
|
+
codesysTimeouts = {
|
|
19
|
+
build: 20 * 60 * 1000,
|
|
20
|
+
hostCommand: 15000,
|
|
21
|
+
runtime: 60000,
|
|
22
|
+
startup: 20 * 60 * 1000,
|
|
23
|
+
stop: 1e4,
|
|
24
|
+
terminate: 5000
|
|
25
|
+
};
|
|
26
|
+
positiveMilliseconds = z.number().int().positive();
|
|
27
|
+
pathSchema = z.string().trim().nonempty();
|
|
28
|
+
wineSchema = z.strictObject({
|
|
29
|
+
prefix: pathSchema,
|
|
30
|
+
binary: pathSchema.default("wine"),
|
|
31
|
+
pathBinary: pathSchema.default("winepath"),
|
|
32
|
+
debug: z.string().default("-all"),
|
|
33
|
+
nativeExit: z.boolean().default(false)
|
|
34
|
+
});
|
|
35
|
+
localCodesysSchema = z.strictObject({
|
|
36
|
+
executable: commandArgumentSchema,
|
|
37
|
+
profile: commandArgumentSchema,
|
|
38
|
+
wine: wineSchema.optional(),
|
|
39
|
+
commandProcessor: pathSchema.default("cmd.exe")
|
|
40
|
+
});
|
|
41
|
+
containerCodesys = {
|
|
42
|
+
executable: "/tmp/codesys-wine/drive_c/CODESYS-3.5.22.30/CODESYS/Common/CODESYS.exe",
|
|
43
|
+
profile: "CODESYS V3.5 SP22 Patch 3",
|
|
44
|
+
wine: { prefix: "/tmp/codesys-wine", nativeExit: true }
|
|
45
|
+
};
|
|
46
|
+
iecName = z.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/);
|
|
47
|
+
cyclicTasksSchema = z.array(z.strictObject({
|
|
48
|
+
name: iecName,
|
|
49
|
+
intervalNanoseconds: z.string().regex(/^[1-9][0-9]*$/).refine((value) => {
|
|
50
|
+
if (!/^[1-9][0-9]*$/.test(value)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const ns = BigInt(value);
|
|
54
|
+
return ns % 1000000n === 0n && ns <= 4294967295000000n;
|
|
55
|
+
}, "Cyclic tasks require an exact positive TIME interval in milliseconds"),
|
|
56
|
+
priority: z.number().int().min(0).max(31),
|
|
57
|
+
programs: z.array(iecName).nonempty()
|
|
58
|
+
})).nonempty().superRefine((tasks, context) => {
|
|
59
|
+
const names = new Set, programs = new Set;
|
|
60
|
+
tasks.forEach((task, index) => {
|
|
61
|
+
if (names.has(task.name.toLowerCase())) {
|
|
62
|
+
context.addIssue({
|
|
63
|
+
code: "custom",
|
|
64
|
+
path: [index, "name"],
|
|
65
|
+
message: "Task names must be unique"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
names.add(task.name.toLowerCase());
|
|
69
|
+
task.programs.forEach((program, position) => {
|
|
70
|
+
if (programs.has(program.toLowerCase())) {
|
|
71
|
+
context.addIssue({
|
|
72
|
+
code: "custom",
|
|
73
|
+
path: [index, "programs", position],
|
|
74
|
+
message: "A program can be scheduled only once"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
programs.add(program.toLowerCase());
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
ioBindingOptions = {
|
|
82
|
+
inverted: z.boolean().optional(),
|
|
83
|
+
shared: z.boolean().optional()
|
|
84
|
+
};
|
|
85
|
+
directIoBindingSchema = z.strictObject({
|
|
86
|
+
address: z.string().regex(/^%[IQ](?:X\d+\.[0-7]|[BWD]\d+)$/),
|
|
87
|
+
type: z.string().optional(),
|
|
88
|
+
...ioBindingOptions
|
|
89
|
+
});
|
|
90
|
+
ethernetSchema = z.strictObject({
|
|
91
|
+
interface: z.string().nonempty().optional(),
|
|
92
|
+
address: z.ipv4().optional(),
|
|
93
|
+
subnet: z.ipv4().optional(),
|
|
94
|
+
gateway: z.ipv4().optional()
|
|
95
|
+
});
|
|
96
|
+
processImageSchema = z.strictObject({
|
|
97
|
+
address: z.string().regex(/^%[IQ]B\d+$/),
|
|
98
|
+
size: z.number().int().positive()
|
|
99
|
+
});
|
|
100
|
+
deviceTreeSchema = z.strictObject({
|
|
101
|
+
ethernet: ethernetSchema.default({}),
|
|
102
|
+
devices: z.array(z.strictObject({
|
|
103
|
+
name: iecName,
|
|
104
|
+
eds: z.string().nonempty(),
|
|
105
|
+
address: z.ipv4().optional(),
|
|
106
|
+
rpiMicroseconds: z.number().int().positive().optional(),
|
|
107
|
+
inputs: processImageSchema.optional(),
|
|
108
|
+
outputs: processImageSchema.optional(),
|
|
109
|
+
modbus: z.strictObject({
|
|
110
|
+
port: z.number().int().positive(),
|
|
111
|
+
registers: z.array(z.strictObject({
|
|
112
|
+
name: iecName,
|
|
113
|
+
offset: z.number().int().nonnegative(),
|
|
114
|
+
value: z.string().regex(/^%QW\d+$/),
|
|
115
|
+
write: z.string().regex(/^%QX\d+\.[0-7]$/),
|
|
116
|
+
status: z.string().regex(/^%IB\d+$/),
|
|
117
|
+
requests: z.string().regex(/^%ID\d+$/)
|
|
118
|
+
}))
|
|
119
|
+
}).optional(),
|
|
120
|
+
comments: z.array(z.strictObject({
|
|
121
|
+
address: z.string().regex(/^%[IQ](?:X\d+\.[0-7]|B\d+)$/),
|
|
122
|
+
text: z.string().nonempty()
|
|
123
|
+
})).default([])
|
|
124
|
+
})).nonempty(),
|
|
125
|
+
mappings: z.array(z.strictObject({
|
|
126
|
+
address: z.string().regex(/^%[IQ](?:X\d+\.[0-7]|B\d+)$/),
|
|
127
|
+
variable: z.string().nonempty()
|
|
128
|
+
})).default([])
|
|
129
|
+
});
|
|
130
|
+
controllerSchema = z.strictObject({
|
|
131
|
+
type: z.number().int().positive(),
|
|
132
|
+
id: z.string().regex(/^[0-9A-F]{4} [0-9A-F]{4}$/),
|
|
133
|
+
version: z.string().regex(/^\d+\.\d+\.\d+\.\d+$/)
|
|
134
|
+
});
|
|
135
|
+
controllerTargetSchema = controllerSchema.pick({ version: true }).extend({
|
|
136
|
+
target: z.enum(["linux-sl", "virtual-linux-arm64-sl"])
|
|
137
|
+
});
|
|
138
|
+
configSchema = z.strictObject({
|
|
139
|
+
io: z.record(z.string(), directIoBindingSchema).optional(),
|
|
140
|
+
deviceTree: deviceTreeSchema.optional(),
|
|
141
|
+
controller: controllerSchema.optional(),
|
|
142
|
+
libraryReferences: z.array(z.string().nonempty()).default([]),
|
|
143
|
+
libraries: z.array(z.strictObject({
|
|
144
|
+
title: z.string(),
|
|
145
|
+
company: z.string().optional(),
|
|
146
|
+
version: z.string().optional(),
|
|
147
|
+
namespace: z.string().optional(),
|
|
148
|
+
path: pathSchema,
|
|
149
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
150
|
+
url: z.string().optional()
|
|
151
|
+
})).optional(),
|
|
152
|
+
docker: z.strictObject({
|
|
153
|
+
cpuSet: z.string().regex(/^\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*$/).optional()
|
|
154
|
+
}).optional(),
|
|
155
|
+
template: pathSchema.optional(),
|
|
156
|
+
sourceDir: pathSchema.default("src"),
|
|
157
|
+
entry: pathSchema.default("src/Main.st"),
|
|
158
|
+
outDir: pathSchema.default("build"),
|
|
159
|
+
task: z.string().nonempty().default("MainTask"),
|
|
160
|
+
tasks: cyclicTasksSchema.optional(),
|
|
161
|
+
removeObjects: z.array(z.string().nonempty()).default([]),
|
|
162
|
+
symbols: z.boolean().default(false),
|
|
163
|
+
online: z.strictObject({
|
|
164
|
+
network: pathSchema.default("bridge"),
|
|
165
|
+
gateway: z.strictObject({
|
|
166
|
+
host: pathSchema,
|
|
167
|
+
port: z.number().int().min(1).max(65535).default(1217)
|
|
168
|
+
}),
|
|
169
|
+
device: z.strictObject({
|
|
170
|
+
host: pathSchema,
|
|
171
|
+
port: z.number().int().min(1).max(65535).default(11740)
|
|
172
|
+
}),
|
|
173
|
+
credentials: z.strictObject({
|
|
174
|
+
usernameEnv: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/),
|
|
175
|
+
passwordEnv: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/)
|
|
176
|
+
}).optional()
|
|
177
|
+
}).optional(),
|
|
178
|
+
timeouts: z.strictObject({
|
|
179
|
+
startup: positiveMilliseconds.default(codesysTimeouts.startup),
|
|
180
|
+
build: positiveMilliseconds.default(codesysTimeouts.build),
|
|
181
|
+
stop: positiveMilliseconds.default(codesysTimeouts.stop),
|
|
182
|
+
terminate: positiveMilliseconds.default(codesysTimeouts.terminate),
|
|
183
|
+
hostCommand: positiveMilliseconds.default(codesysTimeouts.hostCommand),
|
|
184
|
+
runtime: positiveMilliseconds.default(codesysTimeouts.runtime)
|
|
185
|
+
}).prefault({})
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// packages/config/src/compiler.ts
|
|
190
|
+
import { z as z2 } from "zod";
|
|
191
|
+
var durationSchema, sourceExportSchema, taskSchema, targetSchema, common, entryConfigSchema, programsConfigSchema;
|
|
192
|
+
var init_compiler = __esm(() => {
|
|
193
|
+
durationSchema = z2.object({
|
|
194
|
+
kind: z2.literal("duration"),
|
|
195
|
+
nanoseconds: z2.string().regex(/^[1-9][0-9]*$/)
|
|
196
|
+
}).strict();
|
|
197
|
+
sourceExportSchema = z2.object({ module: z2.string().min(1), export: z2.string().min(1) }).strict();
|
|
198
|
+
taskSchema = z2.object({
|
|
199
|
+
name: z2.string().min(1),
|
|
200
|
+
schedule: z2.object({ kind: z2.literal("cyclic"), interval: durationSchema }).strict(),
|
|
201
|
+
priority: z2.number().int().nonnegative(),
|
|
202
|
+
programs: z2.array(z2.string().min(1)).min(1)
|
|
203
|
+
}).strict();
|
|
204
|
+
targetSchema = z2.object({
|
|
205
|
+
kind: z2.string().min(1),
|
|
206
|
+
options: z2.unknown().refine((value) => value !== undefined, { message: "Target options are required." })
|
|
207
|
+
}).strict();
|
|
208
|
+
common = {
|
|
209
|
+
name: z2.string().min(1),
|
|
210
|
+
tsconfig: z2.string().min(1),
|
|
211
|
+
tasks: z2.array(taskSchema).min(1),
|
|
212
|
+
target: targetSchema
|
|
213
|
+
};
|
|
214
|
+
entryConfigSchema = z2.object({ ...common, entry: sourceExportSchema }).strict();
|
|
215
|
+
programsConfigSchema = z2.object({ ...common, programs: z2.record(z2.string().min(1), sourceExportSchema) }).strict();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// packages/config/src/schema.ts
|
|
219
|
+
import { z as z3 } from "zod";
|
|
220
|
+
function rawBuildConfig(config) {
|
|
221
|
+
if (config.compiler)
|
|
222
|
+
throw new Error("Use the compiler build plan for TypeScript projects.");
|
|
223
|
+
if (!config.build)
|
|
224
|
+
throw new Error("Configure build settings.");
|
|
225
|
+
if (!config.tasks)
|
|
226
|
+
return config.build;
|
|
227
|
+
if (config.build.tasks || config.build.task !== undefined)
|
|
228
|
+
throw new Error("Configure the raw ST schedule in tasks or build.tasks/build.task, not both.");
|
|
229
|
+
return {
|
|
230
|
+
...config.build,
|
|
231
|
+
tasks: cyclicTasksSchema.parse(config.tasks.map((task) => ({
|
|
232
|
+
name: task.name,
|
|
233
|
+
intervalNanoseconds: task.schedule.interval.nanoseconds,
|
|
234
|
+
priority: task.priority,
|
|
235
|
+
programs: task.programs
|
|
236
|
+
})))
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
var httpOptionsSchema, ioBindingSchema, assemblySchema, hardwareDeviceSchema, dependencySchema, taskSchema2, monitorSchema, typegenSchema, buildTargetSchema, publicationSchema, hmiTarget, hmiControlSchema, hmiSchema, tsplcConfigSchema;
|
|
240
|
+
var init_schema = __esm(() => {
|
|
241
|
+
init_build_schema();
|
|
242
|
+
init_compiler();
|
|
243
|
+
init_compiler();
|
|
244
|
+
httpOptionsSchema = z3.strictObject({
|
|
245
|
+
timeoutMs: z3.number().int().positive().max(60000).default(2000),
|
|
246
|
+
credentials: z3.array(z3.strictObject({
|
|
247
|
+
originEnv: z3.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),
|
|
248
|
+
bearerTokenEnv: z3.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/)
|
|
249
|
+
})).default([])
|
|
250
|
+
}).default({ timeoutMs: 2000, credentials: [] });
|
|
251
|
+
ioBindingSchema = z3.union([
|
|
252
|
+
directIoBindingSchema,
|
|
253
|
+
z3.strictObject({
|
|
254
|
+
device: z3.string().min(1),
|
|
255
|
+
channel: z3.string().min(1),
|
|
256
|
+
...ioBindingOptions
|
|
257
|
+
})
|
|
258
|
+
]);
|
|
259
|
+
assemblySchema = z3.strictObject({
|
|
260
|
+
assembly: z3.number().int().nonnegative().optional(),
|
|
261
|
+
size: z3.number().int().positive().optional(),
|
|
262
|
+
address: z3.string().regex(/^%[IQ]B\d+$/).optional()
|
|
263
|
+
});
|
|
264
|
+
hardwareDeviceSchema = z3.strictObject({
|
|
265
|
+
file: z3.string().min(1),
|
|
266
|
+
connection: z3.string().min(1).optional(),
|
|
267
|
+
inputs: assemblySchema.optional(),
|
|
268
|
+
outputs: assemblySchema.optional(),
|
|
269
|
+
modbus: z3.strictObject({
|
|
270
|
+
port: z3.number().int().min(1).max(65535).default(502),
|
|
271
|
+
registers: z3.record(z3.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/), z3.number().int().min(0).max(65535))
|
|
272
|
+
}).optional(),
|
|
273
|
+
statusSymbols: z3.record(z3.string(), z3.string()).optional(),
|
|
274
|
+
network: z3.strictObject({
|
|
275
|
+
address: z3.ipv4().optional(),
|
|
276
|
+
rpi: durationSchema.refine((rpi) => BigInt(rpi.nanoseconds) % 1000n === 0n, "An RPI must be a whole number of microseconds.").optional()
|
|
277
|
+
}).optional()
|
|
278
|
+
});
|
|
279
|
+
dependencySchema = z3.union([
|
|
280
|
+
z3.string().regex(/^\d+\.\d+\.\d+\.\d+$/),
|
|
281
|
+
z3.strictObject({
|
|
282
|
+
version: z3.string().regex(/^\d+\.\d+\.\d+\.\d+$/),
|
|
283
|
+
company: z3.string().optional(),
|
|
284
|
+
namespace: z3.string().optional()
|
|
285
|
+
}),
|
|
286
|
+
z3.strictObject({ path: z3.string().min(1), namespace: z3.string().optional() })
|
|
287
|
+
]);
|
|
288
|
+
taskSchema2 = z3.strictObject({
|
|
289
|
+
name: z3.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/),
|
|
290
|
+
schedule: z3.strictObject({ kind: z3.literal("cyclic"), interval: durationSchema }),
|
|
291
|
+
priority: z3.number().int().min(0).max(31),
|
|
292
|
+
programs: z3.array(z3.string().min(1)).nonempty()
|
|
293
|
+
});
|
|
294
|
+
monitorSchema = z3.strictObject({
|
|
295
|
+
endpoint: z3.string().url(),
|
|
296
|
+
namespaceUri: z3.string().optional(),
|
|
297
|
+
symbols: z3.array(z3.string().min(1)).optional(),
|
|
298
|
+
securityMode: z3.enum(["None", "Sign", "SignAndEncrypt"]).default("SignAndEncrypt"),
|
|
299
|
+
securityPolicy: z3.enum(["None", "Basic256Sha256"]).optional(),
|
|
300
|
+
certificateDirectory: z3.string().min(1).default(".tsplc/opcua-pki"),
|
|
301
|
+
username: z3.string().min(1).optional(),
|
|
302
|
+
passwordEnv: z3.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/).optional()
|
|
303
|
+
}).superRefine((monitor, context) => {
|
|
304
|
+
if (monitor.securityPolicy && monitor.securityMode === "None" !== (monitor.securityPolicy === "None"))
|
|
305
|
+
context.addIssue({
|
|
306
|
+
code: "custom",
|
|
307
|
+
path: ["securityPolicy"],
|
|
308
|
+
message: "None mode requires None policy; secure modes require Basic256Sha256."
|
|
309
|
+
});
|
|
310
|
+
if (monitor.passwordEnv && !monitor.username)
|
|
311
|
+
context.addIssue({
|
|
312
|
+
code: "custom",
|
|
313
|
+
path: ["username"],
|
|
314
|
+
message: "Configure username when passwordEnv is used."
|
|
315
|
+
});
|
|
316
|
+
if (monitor.username && monitor.securityMode === "None")
|
|
317
|
+
context.addIssue({
|
|
318
|
+
code: "custom",
|
|
319
|
+
path: ["securityMode"],
|
|
320
|
+
message: "Username authentication requires a secure OPC-UA connection."
|
|
321
|
+
});
|
|
322
|
+
}).transform((monitor) => ({
|
|
323
|
+
...monitor,
|
|
324
|
+
securityPolicy: monitor.securityPolicy ?? (monitor.securityMode === "None" ? "None" : "Basic256Sha256")
|
|
325
|
+
}));
|
|
326
|
+
typegenSchema = z3.strictObject({
|
|
327
|
+
types: z3.union([z3.string(), z3.array(z3.string())]).optional(),
|
|
328
|
+
globals: z3.union([z3.string(), z3.array(z3.string())]).optional(),
|
|
329
|
+
dir: z3.string().default("generated"),
|
|
330
|
+
declarations: z3.boolean().default(true),
|
|
331
|
+
ioTypes: z3.boolean().default(true)
|
|
332
|
+
});
|
|
333
|
+
buildTargetSchema = z3.enum(["production", "development"]);
|
|
334
|
+
publicationSchema = z3.strictObject({
|
|
335
|
+
production: z3.array(z3.string().nonempty()),
|
|
336
|
+
development: z3.array(z3.string().nonempty())
|
|
337
|
+
});
|
|
338
|
+
hmiTarget = z3.string().regex(/^\w+(\.\w+|\[\d+\])+$/);
|
|
339
|
+
hmiControlSchema = z3.discriminatedUnion("kind", [
|
|
340
|
+
z3.strictObject({
|
|
341
|
+
kind: z3.literal("button"),
|
|
342
|
+
label: z3.string().nonempty(),
|
|
343
|
+
target: hmiTarget,
|
|
344
|
+
tone: z3.enum(["start", "stop"]).optional(),
|
|
345
|
+
confirm: z3.boolean().optional()
|
|
346
|
+
}),
|
|
347
|
+
z3.strictObject({
|
|
348
|
+
kind: z3.literal("toggle"),
|
|
349
|
+
label: z3.string().nonempty(),
|
|
350
|
+
target: hmiTarget
|
|
351
|
+
}),
|
|
352
|
+
z3.strictObject({
|
|
353
|
+
kind: z3.literal("slider"),
|
|
354
|
+
label: z3.string().nonempty(),
|
|
355
|
+
target: hmiTarget,
|
|
356
|
+
min: z3.number().int(),
|
|
357
|
+
max: z3.number().int()
|
|
358
|
+
})
|
|
359
|
+
]);
|
|
360
|
+
hmiSchema = z3.strictObject({
|
|
361
|
+
title: z3.string().nonempty(),
|
|
362
|
+
controls: z3.array(hmiControlSchema).default([]),
|
|
363
|
+
conveyors: z3.array(z3.strictObject({
|
|
364
|
+
label: z3.string().nonempty(),
|
|
365
|
+
positions: z3.number().int().positive(),
|
|
366
|
+
diverters: z3.array(z3.number().int().nonnegative()).default([])
|
|
367
|
+
})).default([])
|
|
368
|
+
});
|
|
369
|
+
tsplcConfigSchema = z3.strictObject({
|
|
370
|
+
name: z3.string().default("Application"),
|
|
371
|
+
backend: z3.literal("codesys"),
|
|
372
|
+
publish: publicationSchema.optional(),
|
|
373
|
+
server: z3.strictObject({
|
|
374
|
+
baseUrlEnv: z3.string().optional(),
|
|
375
|
+
transport: z3.enum(["http", "opcua"]).default("http"),
|
|
376
|
+
runtime: z3.strictObject({
|
|
377
|
+
entry: z3.string(),
|
|
378
|
+
target: z3.enum([
|
|
379
|
+
"bun-linux-x64",
|
|
380
|
+
"bun-linux-arm64",
|
|
381
|
+
"bun-darwin-x64",
|
|
382
|
+
"bun-darwin-arm64",
|
|
383
|
+
"bun-windows-x64"
|
|
384
|
+
]).optional()
|
|
385
|
+
}).optional()
|
|
386
|
+
}).optional(),
|
|
387
|
+
compiler: z3.strictObject({
|
|
388
|
+
tsconfig: z3.string().default("tsconfig.json"),
|
|
389
|
+
programs: z3.record(z3.string(), z3.strictObject({ module: z3.string(), export: z3.string() }))
|
|
390
|
+
}).optional(),
|
|
391
|
+
tasks: z3.array(taskSchema2).nonempty().optional(),
|
|
392
|
+
build: configSchema.extend({ task: configSchema.shape.task.unwrap().optional() }).optional(),
|
|
393
|
+
codesys: z3.strictObject({
|
|
394
|
+
http: httpOptionsSchema.optional(),
|
|
395
|
+
programNames: z3.record(z3.string(), z3.string()).optional(),
|
|
396
|
+
deviceTree: z3.strictObject({ ethernet: ethernetSchema.optional() }).optional(),
|
|
397
|
+
controllers: z3.strictObject({
|
|
398
|
+
production: controllerTargetSchema.optional(),
|
|
399
|
+
development: controllerTargetSchema.optional()
|
|
400
|
+
}).optional()
|
|
401
|
+
}).optional(),
|
|
402
|
+
eds: z3.union([z3.string(), z3.array(z3.string())]).default("eds"),
|
|
403
|
+
devices: z3.record(z3.string(), hardwareDeviceSchema).default({}),
|
|
404
|
+
io: z3.record(z3.string(), ioBindingSchema).default({}),
|
|
405
|
+
dependencies: z3.record(z3.string(), dependencySchema).default({}),
|
|
406
|
+
typegen: typegenSchema.optional(),
|
|
407
|
+
monitor: monitorSchema.optional(),
|
|
408
|
+
hmi: hmiSchema.optional()
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// packages/config/src/build.ts
|
|
413
|
+
init_build_schema();
|
|
414
|
+
init_build_schema();
|
|
415
|
+
import { dirname, resolve } from "node:path";
|
|
416
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
417
|
+
var defineBuildConfig = (config) => config;
|
|
418
|
+
var resolveConfig = (input, configFile) => {
|
|
419
|
+
const parsed = configSchema.parse(input);
|
|
420
|
+
const root = dirname(resolve(configFile));
|
|
421
|
+
const codesys = localCodesysSchema.parse(containerCodesys);
|
|
422
|
+
return {
|
|
423
|
+
...parsed,
|
|
424
|
+
docker: parsed.docker ?? {},
|
|
425
|
+
configFile: resolve(configFile),
|
|
426
|
+
template: parsed.template ? resolve(root, parsed.template) : fileURLToPath(new URL("../templates/default.project", import.meta.url)),
|
|
427
|
+
removeObjects: parsed.template ? parsed.removeObjects : ["PLC_PRG", ...parsed.removeObjects],
|
|
428
|
+
libraries: parsed.libraries?.map((library) => ({
|
|
429
|
+
...library,
|
|
430
|
+
path: resolve(root, library.path)
|
|
431
|
+
})),
|
|
432
|
+
sourceDir: resolve(root, parsed.sourceDir),
|
|
433
|
+
entry: resolve(root, parsed.entry),
|
|
434
|
+
outDir: resolve(root, parsed.outDir),
|
|
435
|
+
codesys: {
|
|
436
|
+
...codesys,
|
|
437
|
+
executable: resolve(root, codesys.executable),
|
|
438
|
+
wine: codesys.wine ? { ...codesys.wine, prefix: resolve(root, codesys.wine.prefix) } : undefined
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
};
|
|
442
|
+
var loadConfig = async (file = "tsplc.config.ts") => {
|
|
443
|
+
const path = resolve(file);
|
|
444
|
+
const module = await import(pathToFileURL(path).href);
|
|
445
|
+
if (module.default === undefined && module.config === undefined) {
|
|
446
|
+
throw new Error(`${path} must export a default config`);
|
|
447
|
+
}
|
|
448
|
+
const input = module.default ?? module.config;
|
|
449
|
+
if (input && typeof input === "object" && "build" in input) {
|
|
450
|
+
await Promise.resolve().then(() => init_schema());
|
|
451
|
+
return resolveConfig(rawBuildConfig(tsplcConfigSchema.parse(input)), path);
|
|
452
|
+
}
|
|
453
|
+
return resolveConfig(input, path);
|
|
454
|
+
};
|
|
455
|
+
export {
|
|
456
|
+
codesysTimeouts,
|
|
457
|
+
commandArgumentSchema,
|
|
458
|
+
configSchema,
|
|
459
|
+
containerCodesys,
|
|
460
|
+
controllerSchema,
|
|
461
|
+
cyclicTasksSchema,
|
|
462
|
+
defineBuildConfig,
|
|
463
|
+
deviceTreeSchema,
|
|
464
|
+
directIoBindingSchema,
|
|
465
|
+
dockerImage,
|
|
466
|
+
ethernetSchema,
|
|
467
|
+
loadConfig,
|
|
468
|
+
resolveConfig
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
//# debugId=9151D374B9F1F76C64756E2164756E21
|
|
472
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/build-schema.ts", "../src/compiler.ts", "../src/schema.ts", "../src/build.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { z } from \"zod\";\n\nexport const commandArgumentSchema = z\n .string()\n .refine((value) => value.trim().length > 0, \"Command arguments must not be empty\")\n .refine(\n (value) => !/[\"\\r\\n\\0]/.test(value),\n \"Command arguments must not contain quotes, line breaks, or null bytes\",\n );\n// CODESYS startup and project loading can each take several minutes.\nexport const codesysTimeouts = {\n build: 20 * 60 * 1000,\n hostCommand: 15_000,\n runtime: 60_000,\n startup: 20 * 60 * 1000,\n stop: 10_000,\n terminate: 5000,\n};\n\nconst positiveMilliseconds = z.number().int().positive();\nconst pathSchema = z.string().trim().nonempty();\nconst wineSchema = z.strictObject({\n prefix: pathSchema,\n binary: pathSchema.default(\"wine\"),\n pathBinary: pathSchema.default(\"winepath\"),\n debug: z.string().default(\"-all\"),\n nativeExit: z.boolean().default(false),\n});\nexport const localCodesysSchema = z.strictObject({\n executable: commandArgumentSchema,\n profile: commandArgumentSchema,\n wine: wineSchema.optional(),\n commandProcessor: pathSchema.default(\"cmd.exe\"),\n});\n\n// `tsplc configure` builds this tag; every project compiles with it.\nexport const dockerImage = \"tsplc-build:latest\";\nexport const containerCodesys = {\n executable: \"/tmp/codesys-wine/drive_c/CODESYS-3.5.22.30/CODESYS/Common/CODESYS.exe\",\n profile: \"CODESYS V3.5 SP22 Patch 3\",\n wine: { prefix: \"/tmp/codesys-wine\", nativeExit: true },\n};\nconst iecName = z.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/);\nexport const cyclicTasksSchema = z\n .array(\n z.strictObject({\n name: iecName,\n intervalNanoseconds: z\n .string()\n .regex(/^[1-9][0-9]*$/)\n .refine((value) => {\n if (!/^[1-9][0-9]*$/.test(value)) {\n return false;\n }\n const ns = BigInt(value);\n return ns % 1_000_000n === 0n && ns <= 4_294_967_295_000_000n;\n }, \"Cyclic tasks require an exact positive TIME interval in milliseconds\"),\n priority: z.number().int().min(0).max(31),\n programs: z.array(iecName).nonempty(),\n }),\n )\n .nonempty()\n .superRefine((tasks, context) => {\n const names = new Set<string>(),\n programs = new Set<string>();\n tasks.forEach((task, index) => {\n if (names.has(task.name.toLowerCase())) {\n context.addIssue({\n code: \"custom\",\n path: [index, \"name\"],\n message: \"Task names must be unique\",\n });\n }\n names.add(task.name.toLowerCase());\n task.programs.forEach((program, position) => {\n if (programs.has(program.toLowerCase())) {\n context.addIssue({\n code: \"custom\",\n path: [index, \"programs\", position],\n message: \"A program can be scheduled only once\",\n });\n }\n programs.add(program.toLowerCase());\n });\n });\n });\nexport type CyclicTask = z.infer<typeof cyclicTasksSchema>[number];\n/** `inverted` reads a BOOL input as its opposite; `shared` lets several bindings read one input. */\nexport const ioBindingOptions = {\n inverted: z.boolean().optional(),\n shared: z.boolean().optional(),\n};\n/** A process-image address in CODESYS byte addressing, with an optional IEC type. */\nexport const directIoBindingSchema = z.strictObject({\n address: z.string().regex(/^%[IQ](?:X\\d+\\.[0-7]|[BWD]\\d+)$/),\n type: z.string().optional(),\n ...ioBindingOptions,\n});\n/** The controller's Ethernet interface; omitted settings keep the CODESYS defaults. */\nexport const ethernetSchema = z.strictObject({\n interface: z.string().nonempty().optional(),\n address: z.ipv4().optional(),\n subnet: z.ipv4().optional(),\n gateway: z.ipv4().optional(),\n});\nconst processImageSchema = z.strictObject({\n address: z.string().regex(/^%[IQ]B\\d+$/),\n size: z.number().int().positive(),\n});\n/**\n * An EtherNet/IP scanner tree generated from EDS files. Each adapter's EDS is\n * already reduced to its selected connection and raw byte assemblies, so every\n * payload byte becomes one channel pinned at its region's address plus offset.\n */\nexport const deviceTreeSchema = z.strictObject({\n ethernet: ethernetSchema.default({}),\n devices: z\n .array(\n z.strictObject({\n name: iecName,\n eds: z.string().nonempty(),\n address: z.ipv4().optional(),\n rpiMicroseconds: z.number().int().positive().optional(),\n inputs: processImageSchema.optional(),\n outputs: processImageSchema.optional(),\n // Registers written over Modbus TCP at the adapter's address, with their pinned channels.\n modbus: z\n .strictObject({\n port: z.number().int().positive(),\n registers: z.array(\n z.strictObject({\n name: iecName,\n offset: z.number().int().nonnegative(),\n value: z.string().regex(/^%QW\\d+$/),\n write: z.string().regex(/^%QX\\d+\\.[0-7]$/),\n status: z.string().regex(/^%IB\\d+$/),\n requests: z.string().regex(/^%ID\\d+$/),\n }),\n ),\n })\n .optional(),\n // Channel comments name the logical IO bound at a pinned byte or bit.\n comments: z\n .array(\n z.strictObject({\n address: z.string().regex(/^%[IQ](?:X\\d+\\.[0-7]|B\\d+)$/),\n text: z.string().nonempty(),\n }),\n )\n .default([]),\n }),\n )\n .nonempty(),\n // Variables mapped to pinned bit or byte channels, relative to the application.\n mappings: z\n .array(\n z.strictObject({\n address: z.string().regex(/^%[IQ](?:X\\d+\\.[0-7]|B\\d+)$/),\n variable: z.string().nonempty(),\n }),\n )\n .default([]),\n});\nexport type DeviceTree = z.input<typeof deviceTreeSchema>;\n/** A controller's device repository identity, as CODESYS shows it under Device > Information. */\nexport const controllerSchema = z.strictObject({\n type: z.number().int().positive(),\n id: z.string().regex(/^[0-9A-F]{4} [0-9A-F]{4}$/),\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/),\n});\nexport type Controller = z.infer<typeof controllerSchema>;\n/** A controller the build image carries, named instead of spelled as its repository identity. */\nexport const controllerTargetSchema = controllerSchema.pick({ version: true }).extend({\n target: z.enum([\"linux-sl\", \"virtual-linux-arm64-sl\"]),\n});\nexport const controllerDevices = {\n \"linux-sl\": { type: 4102, id: \"0000 0005\" },\n \"virtual-linux-arm64-sl\": { type: 4096, id: \"0000 1008\" },\n} satisfies Record<z.infer<typeof controllerTargetSchema>[\"target\"], Omit<Controller, \"version\">>;\nexport const configSchema = z.strictObject({\n io: z.record(z.string(), directIoBindingSchema).optional(),\n deviceTree: deviceTreeSchema.optional(),\n // Replaces the template's controller; the build image must carry its description.\n controller: controllerSchema.optional(),\n libraryReferences: z.array(z.string().nonempty()).default([]),\n libraries: z\n .array(\n z.strictObject({\n title: z.string(),\n company: z.string().optional(),\n version: z.string().optional(),\n namespace: z.string().optional(),\n path: pathSchema,\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n url: z.string().optional(),\n }),\n )\n .optional(),\n docker: z\n .strictObject({\n cpuSet: z\n .string()\n .regex(/^\\d+(?:-\\d+)?(?:,\\d+(?:-\\d+)?)*$/)\n .optional(),\n })\n .optional(),\n template: pathSchema.optional(),\n sourceDir: pathSchema.default(\"src\"),\n entry: pathSchema.default(\"src/Main.st\"),\n outDir: pathSchema.default(\"build\"),\n task: z.string().nonempty().default(\"MainTask\"),\n tasks: cyclicTasksSchema.optional(),\n removeObjects: z.array(z.string().nonempty()).default([]),\n symbols: z.boolean().default(false),\n online: z\n .strictObject({\n network: pathSchema.default(\"bridge\"),\n gateway: z.strictObject({\n host: pathSchema,\n port: z.number().int().min(1).max(65535).default(1217),\n }),\n device: z.strictObject({\n host: pathSchema,\n port: z.number().int().min(1).max(65535).default(11740),\n }),\n credentials: z\n .strictObject({\n usernameEnv: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/),\n passwordEnv: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/),\n })\n .optional(),\n })\n .optional(),\n timeouts: z\n .strictObject({\n startup: positiveMilliseconds.default(codesysTimeouts.startup),\n build: positiveMilliseconds.default(codesysTimeouts.build),\n stop: positiveMilliseconds.default(codesysTimeouts.stop),\n terminate: positiveMilliseconds.default(codesysTimeouts.terminate),\n hostCommand: positiveMilliseconds.default(codesysTimeouts.hostCommand),\n runtime: positiveMilliseconds.default(codesysTimeouts.runtime),\n })\n .prefault({}),\n});\nexport type CodesysBuildConfig = z.input<typeof configSchema>;\n",
|
|
6
|
+
"import { z } from \"zod\";\n\ninterface Diagnostic {\n origin: \"config\";\n code: string;\n severity: \"error\";\n message: string;\n}\n\nexport const durationSchema = z\n .object({\n kind: z.literal(\"duration\"),\n nanoseconds: z.string().regex(/^[1-9][0-9]*$/),\n })\n .strict();\n\nexport type Duration = z.infer<typeof durationSchema>;\n\nfunction duration(value: number, scale: number): Duration {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(\"Task duration must be finite and positive.\");\n }\n // Keep task periods exact before serializing them for the compiler/backend.\n const nanoseconds = value * scale;\n if (!Number.isSafeInteger(nanoseconds)) {\n throw new Error(\"Task duration must be an exact, safe number of nanoseconds.\");\n }\n return { kind: \"duration\", nanoseconds: String(nanoseconds) };\n}\n\nexport const ns = (value: number): Duration => duration(value, 1);\nexport const ms = (value: number): Duration => duration(value, 1_000_000);\nexport const seconds = (value: number): Duration => duration(value, 1_000_000_000);\n\nconst sourceExportSchema = z\n .object({ module: z.string().min(1), export: z.string().min(1) })\n .strict();\nconst taskSchema = z\n .object({\n name: z.string().min(1),\n schedule: z.object({ kind: z.literal(\"cyclic\"), interval: durationSchema }).strict(),\n priority: z.number().int().nonnegative(),\n programs: z.array(z.string().min(1)).min(1),\n })\n .strict();\n\n// Shared configuration validates the target envelope. Each backend owns its\n// options schema and hardware-specific scheduling/addressing constraints.\nconst targetSchema = z\n .object({\n kind: z.string().min(1),\n options: z\n .unknown()\n .refine((value) => value !== undefined, { message: \"Target options are required.\" }),\n })\n .strict();\nconst common = {\n name: z.string().min(1),\n tsconfig: z.string().min(1),\n tasks: z.array(taskSchema).min(1),\n target: targetSchema,\n};\nconst entryConfigSchema = z.object({ ...common, entry: sourceExportSchema }).strict();\nconst programsConfigSchema = z\n .object({ ...common, programs: z.record(z.string().min(1), sourceExportSchema) })\n .strict();\n\nexport interface TargetDescriptor<Options = unknown> {\n kind: string;\n options: Options;\n}\nexport type SourceExport = z.infer<typeof sourceExportSchema>;\nexport type TaskConfig = Omit<z.infer<typeof taskSchema>, \"programs\"> & {\n programs: readonly string[];\n};\n\nexport type PlcConfig<Target extends TargetDescriptor = TargetDescriptor> = {\n name: string;\n tsconfig: string;\n tasks: readonly TaskConfig[];\n target: Target;\n} & (\n | { entry: SourceExport; programs?: never }\n | { programs: Readonly<Record<string, SourceExport>>; entry?: never }\n);\n\nexport interface NormalizedConfig {\n name: string;\n tsconfig: string;\n programs: Readonly<Record<string, SourceExport>>;\n tasks: readonly TaskConfig[];\n target: TargetDescriptor;\n}\n\nexport function definePlcConfig<const C extends PlcConfig>(config: C): C {\n return config;\n}\n\nexport function validateConfig(value: unknown): {\n config?: NormalizedConfig;\n diagnostics: readonly Diagnostic[];\n} {\n const multiplePrograms =\n typeof value === \"object\" &&\n value !== null &&\n Object.hasOwn(value, \"programs\") &&\n !Object.hasOwn(value, \"entry\");\n const parsed = (multiplePrograms ? programsConfigSchema : entryConfigSchema).safeParse(value);\n if (!parsed.success) {\n return {\n diagnostics: parsed.error.issues.map((issue) => ({\n origin: \"config\",\n code: \"PLC5001\",\n severity: \"error\",\n message: `${issue.path.join(\".\") || \"config\"}: ${issue.message}`,\n })),\n };\n }\n\n const { data } = parsed;\n const programs = \"entry\" in data ? { main: data.entry } : data.programs;\n const diagnostics: Diagnostic[] = [];\n const report = (message: string): void => {\n diagnostics.push({ origin: \"config\", code: \"PLC5002\", severity: \"error\", message });\n };\n if (Object.keys(programs).length === 0) {\n report(\"At least one program is required.\");\n }\n\n // A program has one scan owner. Preserve task call order while rejecting\n // unknown, duplicated, or unassigned program keys.\n const taskNames = new Set<string>();\n const assigned = new Set<string>();\n for (const task of data.tasks) {\n if (taskNames.has(task.name)) {\n report(`Duplicate task name: ${task.name}.`);\n }\n taskNames.add(task.name);\n for (const program of task.programs) {\n if (!Object.hasOwn(programs, program)) {\n report(`Task ${task.name} references unknown program ${program}.`);\n }\n if (assigned.has(program)) {\n report(`Program ${program} must belong to exactly one task.`);\n }\n assigned.add(program);\n }\n }\n for (const program of Object.keys(programs)) {\n if (!assigned.has(program)) {\n report(`Program ${program} is not assigned to a task.`);\n }\n }\n\n if (diagnostics.length) {\n return { diagnostics };\n }\n return {\n config: {\n name: data.name,\n tsconfig: data.tsconfig,\n programs,\n tasks: data.tasks,\n target: data.target,\n },\n diagnostics,\n };\n}\n",
|
|
7
|
+
"import { z } from \"zod\";\nimport {\n configSchema,\n controllerDevices,\n controllerTargetSchema,\n cyclicTasksSchema,\n directIoBindingSchema,\n ioBindingOptions,\n ethernetSchema,\n type CodesysBuildConfig,\n} from \"./build-schema.ts\";\nimport {\n durationSchema,\n validateConfig as validateCompilerConfig,\n type PlcConfig,\n} from \"./compiler.ts\";\n\nexport {\n ns,\n ms,\n seconds,\n definePlcConfig,\n validateConfig,\n type Duration,\n type NormalizedConfig,\n type PlcConfig,\n type SourceExport,\n type TargetDescriptor,\n type TaskConfig,\n} from \"./compiler.ts\";\nexport type { CodesysBuildConfig, Controller, DeviceTree } from \"./build-schema.ts\";\n\nexport const httpOptionsSchema = z\n .strictObject({\n timeoutMs: z.number().int().positive().max(60000).default(2000),\n credentials: z\n .array(\n z.strictObject({\n originEnv: z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),\n bearerTokenEnv: z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),\n }),\n )\n .default([]),\n })\n .default({ timeoutMs: 2000, credentials: [] });\nexport type HttpOptions = z.infer<typeof httpOptionsSchema>;\n\nconst ioBindingSchema = z.union([\n directIoBindingSchema,\n z.strictObject({\n device: z.string().min(1),\n channel: z.string().min(1),\n ...ioBindingOptions,\n }),\n]);\n// Each field defaults: the assembly from the connection, the size from the EDS and,\n// with a generated device tree, the address from tsPLC's process-image layout.\nconst assemblySchema = z.strictObject({\n assembly: z.number().int().nonnegative().optional(),\n size: z.number().int().positive().optional(),\n address: z\n .string()\n .regex(/^%[IQ]B\\d+$/)\n .optional(),\n});\nconst hardwareDeviceSchema = z.strictObject({\n file: z.string().min(1),\n connection: z.string().min(1).optional(),\n inputs: assemblySchema.optional(),\n outputs: assemblySchema.optional(),\n // Registers the generated device tree writes over Modbus TCP, at network.address.\n // Each maps a name to its wire offset, and is written with FC06 when its write channel rises.\n modbus: z\n .strictObject({\n port: z.number().int().min(1).max(65535).default(502),\n registers: z.record(\n z.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/),\n z.number().int().min(0).max(65535),\n ),\n })\n .optional(),\n statusSymbols: z.record(z.string(), z.string()).optional(),\n // The adapter's network identity in a generated device tree.\n network: z\n .strictObject({\n address: z.ipv4().optional(),\n rpi: durationSchema\n .refine(\n (rpi) => BigInt(rpi.nanoseconds) % 1000n === 0n,\n \"An RPI must be a whole number of microseconds.\",\n )\n .optional(),\n })\n .optional(),\n});\nconst dependencySchema = z.union([\n z.string().regex(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/),\n z.strictObject({\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/),\n company: z.string().optional(),\n namespace: z.string().optional(),\n }),\n z.strictObject({ path: z.string().min(1), namespace: z.string().optional() }),\n]);\nconst taskSchema = z.strictObject({\n name: z.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/),\n schedule: z.strictObject({ kind: z.literal(\"cyclic\"), interval: durationSchema }),\n priority: z.number().int().min(0).max(31),\n programs: z.array(z.string().min(1)).nonempty(),\n});\nconst monitorSchema = z\n .strictObject({\n endpoint: z.string().url(),\n namespaceUri: z.string().optional(),\n symbols: z.array(z.string().min(1)).optional(),\n securityMode: z.enum([\"None\", \"Sign\", \"SignAndEncrypt\"]).default(\"SignAndEncrypt\"),\n securityPolicy: z.enum([\"None\", \"Basic256Sha256\"]).optional(),\n certificateDirectory: z.string().min(1).default(\".tsplc/opcua-pki\"),\n username: z.string().min(1).optional(),\n passwordEnv: z\n .string()\n .regex(/^[A-Za-z_][A-Za-z_0-9]*$/)\n .optional(),\n })\n .superRefine((monitor, context) => {\n if (\n monitor.securityPolicy &&\n (monitor.securityMode === \"None\") !== (monitor.securityPolicy === \"None\")\n )\n context.addIssue({\n code: \"custom\",\n path: [\"securityPolicy\"],\n message: \"None mode requires None policy; secure modes require Basic256Sha256.\",\n });\n if (monitor.passwordEnv && !monitor.username)\n context.addIssue({\n code: \"custom\",\n path: [\"username\"],\n message: \"Configure username when passwordEnv is used.\",\n });\n if (monitor.username && monitor.securityMode === \"None\")\n context.addIssue({\n code: \"custom\",\n path: [\"securityMode\"],\n message: \"Username authentication requires a secure OPC-UA connection.\",\n });\n })\n .transform((monitor) => ({\n ...monitor,\n securityPolicy:\n monitor.securityPolicy ??\n (monitor.securityMode === \"None\" ? (\"None\" as const) : (\"Basic256Sha256\" as const)),\n }));\nexport const typegenSchema = z.strictObject({\n types: z.union([z.string(), z.array(z.string())]).optional(),\n globals: z.union([z.string(), z.array(z.string())]).optional(),\n /** Directory for the generated `plc.ts`, `hardware.ts` and `machines.ts`. */\n dir: z.string().default(\"generated\"),\n /** Emit TypeScript declarations in `plc.ts`, not just the runtime field and symbol tables. */\n declarations: z.boolean().default(true),\n /** Emit the I/O binding types and device catalog in `hardware.ts`, not just the publication selectors. */\n ioTypes: z.boolean().default(true),\n});\nexport const buildTargetSchema = z.enum([\"production\", \"development\"]);\nexport type BuildTarget = z.infer<typeof buildTargetSchema>;\nexport const publicationSchema = z.strictObject({\n production: z.array(z.string().nonempty()),\n development: z.array(z.string().nonempty()),\n});\nexport type Publication = Readonly<Record<BuildTarget, readonly string[]>>;\n/** A published PLC variable, as `Global.Field`. */\nconst hmiTarget = z.string().regex(/^\\w+(\\.\\w+|\\[\\d+\\])+$/);\nconst hmiControlSchema = z.discriminatedUnion(\"kind\", [\n /** Pulses a BOOL on for 200 ms, like a pushbutton. */\n z.strictObject({\n kind: z.literal(\"button\"),\n label: z.string().nonempty(),\n target: hmiTarget,\n tone: z.enum([\"start\", \"stop\"]).optional(),\n /** Ask before pressing, for controls that start motion. */\n confirm: z.boolean().optional(),\n }),\n /** Switches a BOOL on or off, and shows its current state. */\n z.strictObject({\n kind: z.literal(\"toggle\"),\n label: z.string().nonempty(),\n target: hmiTarget,\n }),\n /** Writes an integer when released, and shows its current value. */\n z.strictObject({\n kind: z.literal(\"slider\"),\n label: z.string().nonempty(),\n target: hmiTarget,\n min: z.number().int(),\n max: z.number().int(),\n }),\n]);\nexport const hmiSchema = z.strictObject({\n title: z.string().nonempty(),\n controls: z.array(hmiControlSchema).default([]),\n /** The PLC reports whether each position of these conveyors is occupied, in this order. */\n conveyors: z\n .array(\n z.strictObject({\n label: z.string().nonempty(),\n positions: z.number().int().positive(),\n /** Positions that are diverters, drawn differently. */\n diverters: z.array(z.number().int().nonnegative()).default([]),\n }),\n )\n .default([]),\n});\nexport type HmiConfig = z.input<typeof hmiSchema>;\nexport type ResolvedHmiConfig = z.output<typeof hmiSchema>;\n\nexport const tsplcConfigSchema = z.strictObject({\n name: z.string().default(\"Application\"),\n backend: z.literal(\"codesys\"),\n publish: publicationSchema.optional(),\n server: z\n .strictObject({\n baseUrlEnv: z.string().optional(),\n transport: z.enum([\"http\", \"opcua\"]).default(\"http\"),\n runtime: z\n .strictObject({\n entry: z.string(),\n target: z\n .enum([\n \"bun-linux-x64\",\n \"bun-linux-arm64\",\n \"bun-darwin-x64\",\n \"bun-darwin-arm64\",\n \"bun-windows-x64\",\n ])\n .optional(),\n })\n .optional(),\n })\n .optional(),\n compiler: z\n .strictObject({\n tsconfig: z.string().default(\"tsconfig.json\"),\n programs: z.record(z.string(), z.strictObject({ module: z.string(), export: z.string() })),\n })\n .optional(),\n tasks: z.array(taskSchema).nonempty().optional(),\n // Keep an authored legacy task distinguishable from resolveConfig's default.\n // An explicit shared schedule must have a single owner.\n build: configSchema.extend({ task: configSchema.shape.task.unwrap().optional() }).optional(),\n codesys: z\n .strictObject({\n http: httpOptionsSchema.optional(),\n programNames: z.record(z.string(), z.string()).optional(),\n // Generate an EtherNet/IP scanner with one adapter per entry in devices.\n deviceTree: z.strictObject({ ethernet: ethernetSchema.optional() }).optional(),\n // Each omitted controller keeps the template's device. See controllerFor.\n controllers: z\n .strictObject({\n production: controllerTargetSchema.optional(),\n development: controllerTargetSchema.optional(),\n })\n .optional(),\n })\n .optional(),\n eds: z.union([z.string(), z.array(z.string())]).default(\"eds\"),\n devices: z.record(z.string(), hardwareDeviceSchema).default({}),\n io: z.record(z.string(), ioBindingSchema).default({}),\n dependencies: z.record(z.string(), dependencySchema).default({}),\n // Raw ST builds opt into PLC contract generation by configuring this section.\n typegen: typegenSchema.optional(),\n monitor: monitorSchema.optional(),\n hmi: hmiSchema.optional(),\n});\nexport type TsplcConfig = z.input<typeof tsplcConfigSchema>;\nexport type ResolvedTsplcConfig = z.output<typeof tsplcConfigSchema>;\nexport type HardwareDevice = z.infer<typeof hardwareDeviceSchema>;\nexport type LibraryDependency = z.infer<typeof dependencySchema>;\n\n/**\n * `build` compiles for the production controller. `run` and controller\n * operations target the local runtime, so they compile for the development one.\n */\nexport const buildTargetFor = (command: string): BuildTarget =>\n [\"run\", \"download\", \"online-change\", \"inspect\"].includes(command) ? \"development\" : \"production\";\nexport const controllerFor = (config: ResolvedTsplcConfig, command: string) => {\n const controller = config.codesys?.controllers?.[buildTargetFor(command)];\n return controller && { ...controllerDevices[controller.target], version: controller.version };\n};\n\n/**\n * The project without fieldbus I/O, for a plant simulator that writes inputs over\n * OPC UA: fieldbus input copies would overwrite those writes every scan.\n */\nexport const simulationConfig = (config: ResolvedTsplcConfig): ResolvedTsplcConfig => ({\n ...config,\n eds: [],\n devices: {},\n io: {},\n ...(config.codesys && {\n codesys: {\n ...config.codesys,\n deviceTree: undefined,\n },\n }),\n});\n\n/** All paths are relative to this file; no package has a second project config. */\nexport function defineConfig<const C extends TsplcConfig>(config: C): C {\n return config;\n}\n\n/** Raw ST program names already are IEC names; use the shared schedule directly. */\nexport function rawBuildConfig(config: ResolvedTsplcConfig): CodesysBuildConfig {\n if (config.compiler) throw new Error(\"Use the compiler build plan for TypeScript projects.\");\n if (!config.build) throw new Error(\"Configure build settings.\");\n if (!config.tasks) return config.build;\n if (config.build.tasks || config.build.task !== undefined)\n throw new Error(\"Configure the raw ST schedule in tasks or build.tasks/build.task, not both.\");\n return {\n ...config.build,\n tasks: cyclicTasksSchema.parse(\n config.tasks.map((task) => ({\n name: task.name,\n intervalNanoseconds: task.schedule.interval.nanoseconds,\n priority: task.priority,\n programs: task.programs,\n })),\n ),\n };\n}\n\n/** Adapt the shared project to the compiler's backend-independent scan model. */\nexport function compilerConfig(\n config: ResolvedTsplcConfig,\n io: Record<string, { address: string; type?: string }>,\n buildTarget: BuildTarget = \"production\",\n) {\n if (!config.compiler || !config.tasks)\n throw new Error(\"This project uses raw Structured Text; no TypeScript compiler is configured.\");\n // The device tree and controllers are build-time engineering; the compiler only sees addresses.\n const { deviceTree: _deviceTree, controllers: _controllers, ...codesys } = config.codesys ?? {};\n const value: PlcConfig = {\n name: config.name,\n tsconfig: config.compiler.tsconfig,\n programs: config.compiler.programs,\n tasks: config.tasks,\n target: {\n kind: config.backend,\n options: {\n ...codesys,\n publish: config.publish,\n buildTarget,\n io: Object.fromEntries(\n Object.entries(io).map(([name, binding]) => [\n name,\n {\n kind: \"direct\",\n ...binding,\n ...(mappedChannel(config, name, binding) && { mapped: true }),\n },\n ]),\n ),\n engineering: {\n kind: \"v3.5\",\n ...(config.build ? { build: compilerBuildOptions(config.build) } : {}),\n },\n },\n },\n };\n const validated = validateCompilerConfig(value);\n if (!validated.config)\n throw new Error(validated.diagnostics.map((item) => item.message).join(\"\\n\"));\n return validated.config;\n}\n\n/**\n * A generated device tree maps a device's bit or byte scalar to its variable in the\n * I/O mapping. Wider values span several byte channels and keep an AT declaration.\n */\nfunction mappedChannel(\n config: ResolvedTsplcConfig,\n name: string,\n binding: { address: string; type?: string; inverted?: boolean; shared?: boolean },\n) {\n const source = config.io[name];\n return (\n config.codesys?.deviceTree !== undefined &&\n source !== undefined &&\n \"device\" in source &&\n // A channel maps to one variable as it stands, so these need an AT wire and a copy.\n !binding.inverted &&\n !binding.shared &&\n /^%[IQ][XB]/.test(binding.address) &&\n !/^ARRAY/i.test(binding.type ?? \"\")\n );\n}\n\nfunction compilerBuildOptions(build: CodesysBuildConfig) {\n const {\n sourceDir: _source,\n entry: _entry,\n outDir: _out,\n task: _task,\n tasks: _tasks,\n ...settings\n } = build;\n return settings;\n}\n",
|
|
8
|
+
"import { dirname, resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport type { z } from \"zod\";\nimport {\n configSchema,\n containerCodesys,\n localCodesysSchema,\n type CodesysBuildConfig,\n} from \"./build-schema.ts\";\nexport {\n commandArgumentSchema,\n codesysTimeouts,\n dockerImage,\n containerCodesys,\n cyclicTasksSchema,\n directIoBindingSchema,\n ethernetSchema,\n deviceTreeSchema,\n controllerSchema,\n configSchema,\n type CyclicTask,\n type DeviceTree,\n type Controller,\n type CodesysBuildConfig,\n} from \"./build-schema.ts\";\n\nexport type ResolvedConfig = z.output<typeof configSchema> & {\n template: string;\n configFile: string;\n codesys: z.output<typeof localCodesysSchema>;\n};\n\n/** Keep config authoring typed; validation and relative path resolution happen at load. */\nexport const defineBuildConfig = (config: CodesysBuildConfig): CodesysBuildConfig => config;\n\nexport const resolveConfig = (input: unknown, configFile: string): ResolvedConfig => {\n const parsed = configSchema.parse(input);\n const root = dirname(resolve(configFile));\n const codesys = localCodesysSchema.parse(containerCodesys);\n return {\n ...parsed,\n docker: parsed.docker ?? {},\n configFile: resolve(configFile),\n template: parsed.template\n ? resolve(root, parsed.template)\n : fileURLToPath(new URL(\"../templates/default.project\", import.meta.url)),\n removeObjects: parsed.template ? parsed.removeObjects : [\"PLC_PRG\", ...parsed.removeObjects],\n libraries: parsed.libraries?.map((library) => ({\n ...library,\n path: resolve(root, library.path),\n })),\n sourceDir: resolve(root, parsed.sourceDir),\n entry: resolve(root, parsed.entry),\n outDir: resolve(root, parsed.outDir),\n codesys: {\n ...codesys,\n executable: resolve(root, codesys.executable),\n wine: codesys.wine\n ? { ...codesys.wine, prefix: resolve(root, codesys.wine.prefix) }\n : undefined,\n },\n };\n};\n\nexport const loadConfig = async (file = \"tsplc.config.ts\") => {\n const path = resolve(file);\n const module = (await import(pathToFileURL(path).href)) as {\n config?: unknown;\n default?: unknown;\n };\n if (module.default === undefined && module.config === undefined) {\n throw new Error(`${path} must export a default config`);\n }\n const input = module.default ?? module.config;\n if (input && typeof input === \"object\" && \"build\" in input) {\n const { rawBuildConfig, tsplcConfigSchema } = await import(\"./schema.ts\");\n return resolveConfig(rawBuildConfig(tsplcConfigSchema.parse(input)), path);\n }\n return resolveConfig(input, path);\n};\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "9151D374B9F1F76C64756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|