@tsplc/config 0.0.0-stage → 0.2.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.js ADDED
@@ -0,0 +1,574 @@
1
+ // packages/config/src/schema.ts
2
+ import { z as z3 } from "zod";
3
+
4
+ // packages/config/src/build-schema.ts
5
+ import { z } from "zod";
6
+ var 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");
7
+ var codesysTimeouts = {
8
+ build: 20 * 60 * 1000,
9
+ hostCommand: 15000,
10
+ runtime: 60000,
11
+ startup: 20 * 60 * 1000,
12
+ stop: 1e4,
13
+ terminate: 5000
14
+ };
15
+ var positiveMilliseconds = z.number().int().positive();
16
+ var pathSchema = z.string().trim().nonempty();
17
+ var wineSchema = z.strictObject({
18
+ prefix: pathSchema,
19
+ binary: pathSchema.default("wine"),
20
+ pathBinary: pathSchema.default("winepath"),
21
+ debug: z.string().default("-all"),
22
+ nativeExit: z.boolean().default(false)
23
+ });
24
+ var localCodesysSchema = z.strictObject({
25
+ executable: commandArgumentSchema,
26
+ profile: commandArgumentSchema,
27
+ wine: wineSchema.optional(),
28
+ commandProcessor: pathSchema.default("cmd.exe")
29
+ });
30
+ var iecName = z.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/);
31
+ var cyclicTasksSchema = z.array(z.strictObject({
32
+ name: iecName,
33
+ intervalNanoseconds: z.string().regex(/^[1-9][0-9]*$/).refine((value) => {
34
+ if (!/^[1-9][0-9]*$/.test(value)) {
35
+ return false;
36
+ }
37
+ const ns = BigInt(value);
38
+ return ns % 1000000n === 0n && ns <= 4294967295000000n;
39
+ }, "Cyclic tasks require an exact positive TIME interval in milliseconds"),
40
+ priority: z.number().int().min(0).max(31),
41
+ programs: z.array(iecName).nonempty()
42
+ })).nonempty().superRefine((tasks, context) => {
43
+ const names = new Set, programs = new Set;
44
+ tasks.forEach((task, index) => {
45
+ if (names.has(task.name.toLowerCase())) {
46
+ context.addIssue({
47
+ code: "custom",
48
+ path: [index, "name"],
49
+ message: "Task names must be unique"
50
+ });
51
+ }
52
+ names.add(task.name.toLowerCase());
53
+ task.programs.forEach((program, position) => {
54
+ if (programs.has(program.toLowerCase())) {
55
+ context.addIssue({
56
+ code: "custom",
57
+ path: [index, "programs", position],
58
+ message: "A program can be scheduled only once"
59
+ });
60
+ }
61
+ programs.add(program.toLowerCase());
62
+ });
63
+ });
64
+ });
65
+ var ioBindingOptions = {
66
+ inverted: z.boolean().optional(),
67
+ shared: z.boolean().optional()
68
+ };
69
+ var directIoBindingSchema = z.strictObject({
70
+ address: z.string().regex(/^%[IQ](?:X\d+\.[0-7]|[BWD]\d+)$/),
71
+ type: z.string().optional(),
72
+ ...ioBindingOptions
73
+ });
74
+ var ethernetSchema = z.strictObject({
75
+ interface: z.string().nonempty().optional(),
76
+ address: z.ipv4().optional(),
77
+ subnet: z.ipv4().optional(),
78
+ gateway: z.ipv4().optional()
79
+ });
80
+ var processImageSchema = z.strictObject({
81
+ address: z.string().regex(/^%[IQ]B\d+$/),
82
+ size: z.number().int().positive()
83
+ });
84
+ var deviceTreeSchema = z.strictObject({
85
+ ethernet: ethernetSchema.default({}),
86
+ devices: z.array(z.strictObject({
87
+ name: iecName,
88
+ eds: z.string().nonempty(),
89
+ address: z.ipv4().optional(),
90
+ rpiMicroseconds: z.number().int().positive().optional(),
91
+ inputs: processImageSchema.optional(),
92
+ outputs: processImageSchema.optional(),
93
+ modbus: z.strictObject({
94
+ port: z.number().int().positive(),
95
+ registers: z.array(z.strictObject({
96
+ name: iecName,
97
+ offset: z.number().int().nonnegative(),
98
+ value: z.string().regex(/^%QW\d+$/),
99
+ write: z.string().regex(/^%QX\d+\.[0-7]$/),
100
+ status: z.string().regex(/^%IB\d+$/),
101
+ requests: z.string().regex(/^%ID\d+$/)
102
+ }))
103
+ }).optional(),
104
+ comments: z.array(z.strictObject({
105
+ address: z.string().regex(/^%[IQ](?:X\d+\.[0-7]|B\d+)$/),
106
+ text: z.string().nonempty()
107
+ })).default([])
108
+ })).nonempty(),
109
+ mappings: z.array(z.strictObject({
110
+ address: z.string().regex(/^%[IQ](?:X\d+\.[0-7]|B\d+)$/),
111
+ variable: z.string().nonempty()
112
+ })).default([])
113
+ });
114
+ var controllerSchema = z.strictObject({
115
+ type: z.number().int().positive(),
116
+ id: z.string().regex(/^[0-9A-F]{4} [0-9A-F]{4}$/),
117
+ version: z.string().regex(/^\d+\.\d+\.\d+\.\d+$/)
118
+ });
119
+ var controllerTargetSchema = controllerSchema.pick({ version: true }).extend({
120
+ target: z.enum(["linux-sl", "virtual-linux-arm64-sl"])
121
+ });
122
+ var controllerDevices = {
123
+ "linux-sl": { type: 4102, id: "0000 0005" },
124
+ "virtual-linux-arm64-sl": { type: 4096, id: "0000 1008" }
125
+ };
126
+ var configSchema = z.strictObject({
127
+ io: z.record(z.string(), directIoBindingSchema).optional(),
128
+ deviceTree: deviceTreeSchema.optional(),
129
+ controller: controllerSchema.optional(),
130
+ libraryReferences: z.array(z.string().nonempty()).default([]),
131
+ libraries: z.array(z.strictObject({
132
+ title: z.string(),
133
+ company: z.string().optional(),
134
+ version: z.string().optional(),
135
+ namespace: z.string().optional(),
136
+ path: pathSchema,
137
+ sha256: z.string().regex(/^[a-f0-9]{64}$/),
138
+ url: z.string().optional()
139
+ })).optional(),
140
+ docker: z.strictObject({
141
+ cpuSet: z.string().regex(/^\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*$/).optional()
142
+ }).optional(),
143
+ template: pathSchema.optional(),
144
+ sourceDir: pathSchema.default("src"),
145
+ entry: pathSchema.default("src/Main.st"),
146
+ outDir: pathSchema.default("build"),
147
+ task: z.string().nonempty().default("MainTask"),
148
+ tasks: cyclicTasksSchema.optional(),
149
+ removeObjects: z.array(z.string().nonempty()).default([]),
150
+ symbols: z.boolean().default(false),
151
+ online: z.strictObject({
152
+ network: pathSchema.default("bridge"),
153
+ gateway: z.strictObject({
154
+ host: pathSchema,
155
+ port: z.number().int().min(1).max(65535).default(1217)
156
+ }),
157
+ device: z.strictObject({
158
+ host: pathSchema,
159
+ port: z.number().int().min(1).max(65535).default(11740)
160
+ }),
161
+ credentials: z.strictObject({
162
+ usernameEnv: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/),
163
+ passwordEnv: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/)
164
+ }).optional()
165
+ }).optional(),
166
+ timeouts: z.strictObject({
167
+ startup: positiveMilliseconds.default(codesysTimeouts.startup),
168
+ build: positiveMilliseconds.default(codesysTimeouts.build),
169
+ stop: positiveMilliseconds.default(codesysTimeouts.stop),
170
+ terminate: positiveMilliseconds.default(codesysTimeouts.terminate),
171
+ hostCommand: positiveMilliseconds.default(codesysTimeouts.hostCommand),
172
+ runtime: positiveMilliseconds.default(codesysTimeouts.runtime)
173
+ }).prefault({})
174
+ });
175
+
176
+ // packages/config/src/compiler.ts
177
+ import { z as z2 } from "zod";
178
+ var durationSchema = z2.object({
179
+ kind: z2.literal("duration"),
180
+ nanoseconds: z2.string().regex(/^[1-9][0-9]*$/)
181
+ }).strict();
182
+ function duration(value, scale) {
183
+ if (!Number.isFinite(value) || value <= 0) {
184
+ throw new Error("Task duration must be finite and positive.");
185
+ }
186
+ const nanoseconds = value * scale;
187
+ if (!Number.isSafeInteger(nanoseconds)) {
188
+ throw new Error("Task duration must be an exact, safe number of nanoseconds.");
189
+ }
190
+ return { kind: "duration", nanoseconds: String(nanoseconds) };
191
+ }
192
+ var ns = (value) => duration(value, 1);
193
+ var ms = (value) => duration(value, 1e6);
194
+ var seconds = (value) => duration(value, 1e9);
195
+ var sourceExportSchema = z2.object({ module: z2.string().min(1), export: z2.string().min(1) }).strict();
196
+ var taskSchema = z2.object({
197
+ name: z2.string().min(1),
198
+ schedule: z2.object({ kind: z2.literal("cyclic"), interval: durationSchema }).strict(),
199
+ priority: z2.number().int().nonnegative(),
200
+ programs: z2.array(z2.string().min(1)).min(1)
201
+ }).strict();
202
+ var targetSchema = z2.object({
203
+ kind: z2.string().min(1),
204
+ options: z2.unknown().refine((value) => value !== undefined, { message: "Target options are required." })
205
+ }).strict();
206
+ var common = {
207
+ name: z2.string().min(1),
208
+ tsconfig: z2.string().min(1),
209
+ tasks: z2.array(taskSchema).min(1),
210
+ target: targetSchema
211
+ };
212
+ var entryConfigSchema = z2.object({ ...common, entry: sourceExportSchema }).strict();
213
+ var programsConfigSchema = z2.object({ ...common, programs: z2.record(z2.string().min(1), sourceExportSchema) }).strict();
214
+ function definePlcConfig(config) {
215
+ return config;
216
+ }
217
+ function validateConfig(value) {
218
+ const multiplePrograms = typeof value === "object" && value !== null && Object.hasOwn(value, "programs") && !Object.hasOwn(value, "entry");
219
+ const parsed = (multiplePrograms ? programsConfigSchema : entryConfigSchema).safeParse(value);
220
+ if (!parsed.success) {
221
+ return {
222
+ diagnostics: parsed.error.issues.map((issue) => ({
223
+ origin: "config",
224
+ code: "PLC5001",
225
+ severity: "error",
226
+ message: `${issue.path.join(".") || "config"}: ${issue.message}`
227
+ }))
228
+ };
229
+ }
230
+ const { data } = parsed;
231
+ const programs = "entry" in data ? { main: data.entry } : data.programs;
232
+ const diagnostics = [];
233
+ const report = (message) => {
234
+ diagnostics.push({ origin: "config", code: "PLC5002", severity: "error", message });
235
+ };
236
+ if (Object.keys(programs).length === 0) {
237
+ report("At least one program is required.");
238
+ }
239
+ const taskNames = new Set;
240
+ const assigned = new Set;
241
+ for (const task of data.tasks) {
242
+ if (taskNames.has(task.name)) {
243
+ report(`Duplicate task name: ${task.name}.`);
244
+ }
245
+ taskNames.add(task.name);
246
+ for (const program of task.programs) {
247
+ if (!Object.hasOwn(programs, program)) {
248
+ report(`Task ${task.name} references unknown program ${program}.`);
249
+ }
250
+ if (assigned.has(program)) {
251
+ report(`Program ${program} must belong to exactly one task.`);
252
+ }
253
+ assigned.add(program);
254
+ }
255
+ }
256
+ for (const program of Object.keys(programs)) {
257
+ if (!assigned.has(program)) {
258
+ report(`Program ${program} is not assigned to a task.`);
259
+ }
260
+ }
261
+ if (diagnostics.length) {
262
+ return { diagnostics };
263
+ }
264
+ return {
265
+ config: {
266
+ name: data.name,
267
+ tsconfig: data.tsconfig,
268
+ programs,
269
+ tasks: data.tasks,
270
+ target: data.target
271
+ },
272
+ diagnostics
273
+ };
274
+ }
275
+
276
+ // packages/config/src/schema.ts
277
+ var httpOptionsSchema = z3.strictObject({
278
+ timeoutMs: z3.number().int().positive().max(60000).default(2000),
279
+ credentials: z3.array(z3.strictObject({
280
+ originEnv: z3.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),
281
+ bearerTokenEnv: z3.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/)
282
+ })).default([])
283
+ }).default({ timeoutMs: 2000, credentials: [] });
284
+ var ioBindingSchema = z3.union([
285
+ directIoBindingSchema,
286
+ z3.strictObject({
287
+ device: z3.string().min(1),
288
+ channel: z3.string().min(1),
289
+ ...ioBindingOptions
290
+ })
291
+ ]);
292
+ var assemblySchema = z3.strictObject({
293
+ assembly: z3.number().int().nonnegative().optional(),
294
+ size: z3.number().int().positive().optional(),
295
+ address: z3.string().regex(/^%[IQ]B\d+$/).optional()
296
+ });
297
+ var hardwareDeviceSchema = z3.strictObject({
298
+ file: z3.string().min(1),
299
+ connection: z3.string().min(1).optional(),
300
+ inputs: assemblySchema.optional(),
301
+ outputs: assemblySchema.optional(),
302
+ modbus: z3.strictObject({
303
+ port: z3.number().int().min(1).max(65535).default(502),
304
+ registers: z3.record(z3.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/), z3.number().int().min(0).max(65535))
305
+ }).optional(),
306
+ statusSymbols: z3.record(z3.string(), z3.string()).optional(),
307
+ network: z3.strictObject({
308
+ address: z3.ipv4().optional(),
309
+ rpi: durationSchema.refine((rpi) => BigInt(rpi.nanoseconds) % 1000n === 0n, "An RPI must be a whole number of microseconds.").optional()
310
+ }).optional()
311
+ });
312
+ var dependencySchema = z3.union([
313
+ z3.string().regex(/^\d+\.\d+\.\d+\.\d+$/),
314
+ z3.strictObject({
315
+ version: z3.string().regex(/^\d+\.\d+\.\d+\.\d+$/),
316
+ company: z3.string().optional(),
317
+ namespace: z3.string().optional()
318
+ }),
319
+ z3.strictObject({ path: z3.string().min(1), namespace: z3.string().optional() })
320
+ ]);
321
+ var taskSchema2 = z3.strictObject({
322
+ name: z3.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/),
323
+ schedule: z3.strictObject({ kind: z3.literal("cyclic"), interval: durationSchema }),
324
+ priority: z3.number().int().min(0).max(31),
325
+ programs: z3.array(z3.string().min(1)).nonempty()
326
+ });
327
+ var monitorSchema = z3.strictObject({
328
+ endpoint: z3.string().url(),
329
+ namespaceUri: z3.string().optional(),
330
+ symbols: z3.array(z3.string().min(1)).optional(),
331
+ securityMode: z3.enum(["None", "Sign", "SignAndEncrypt"]).default("SignAndEncrypt"),
332
+ securityPolicy: z3.enum(["None", "Basic256Sha256"]).optional(),
333
+ certificateDirectory: z3.string().min(1).default(".tsplc/opcua-pki"),
334
+ username: z3.string().min(1).optional(),
335
+ passwordEnv: z3.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/).optional()
336
+ }).superRefine((monitor, context) => {
337
+ if (monitor.securityPolicy && monitor.securityMode === "None" !== (monitor.securityPolicy === "None"))
338
+ context.addIssue({
339
+ code: "custom",
340
+ path: ["securityPolicy"],
341
+ message: "None mode requires None policy; secure modes require Basic256Sha256."
342
+ });
343
+ if (monitor.passwordEnv && !monitor.username)
344
+ context.addIssue({
345
+ code: "custom",
346
+ path: ["username"],
347
+ message: "Configure username when passwordEnv is used."
348
+ });
349
+ if (monitor.username && monitor.securityMode === "None")
350
+ context.addIssue({
351
+ code: "custom",
352
+ path: ["securityMode"],
353
+ message: "Username authentication requires a secure OPC-UA connection."
354
+ });
355
+ }).transform((monitor) => ({
356
+ ...monitor,
357
+ securityPolicy: monitor.securityPolicy ?? (monitor.securityMode === "None" ? "None" : "Basic256Sha256")
358
+ }));
359
+ var typegenSchema = z3.strictObject({
360
+ types: z3.union([z3.string(), z3.array(z3.string())]).optional(),
361
+ globals: z3.union([z3.string(), z3.array(z3.string())]).optional(),
362
+ dir: z3.string().default("generated"),
363
+ declarations: z3.boolean().default(true),
364
+ ioTypes: z3.boolean().default(true)
365
+ });
366
+ var buildTargetSchema = z3.enum(["production", "development"]);
367
+ var publicationSchema = z3.strictObject({
368
+ production: z3.array(z3.string().nonempty()),
369
+ development: z3.array(z3.string().nonempty())
370
+ });
371
+ var hmiTarget = z3.string().regex(/^\w+(\.\w+|\[\d+\])+$/);
372
+ var hmiControlSchema = z3.discriminatedUnion("kind", [
373
+ z3.strictObject({
374
+ kind: z3.literal("button"),
375
+ label: z3.string().nonempty(),
376
+ target: hmiTarget,
377
+ tone: z3.enum(["start", "stop"]).optional(),
378
+ confirm: z3.boolean().optional()
379
+ }),
380
+ z3.strictObject({
381
+ kind: z3.literal("toggle"),
382
+ label: z3.string().nonempty(),
383
+ target: hmiTarget
384
+ }),
385
+ z3.strictObject({
386
+ kind: z3.literal("slider"),
387
+ label: z3.string().nonempty(),
388
+ target: hmiTarget,
389
+ min: z3.number().int(),
390
+ max: z3.number().int()
391
+ })
392
+ ]);
393
+ var hmiSchema = z3.strictObject({
394
+ title: z3.string().nonempty(),
395
+ controls: z3.array(hmiControlSchema).default([]),
396
+ conveyors: z3.array(z3.strictObject({
397
+ label: z3.string().nonempty(),
398
+ positions: z3.number().int().positive(),
399
+ diverters: z3.array(z3.number().int().nonnegative()).default([])
400
+ })).default([])
401
+ });
402
+ var tsplcConfigSchema = z3.strictObject({
403
+ name: z3.string().default("Application"),
404
+ backend: z3.literal("codesys"),
405
+ publish: publicationSchema.optional(),
406
+ server: z3.strictObject({
407
+ baseUrlEnv: z3.string().optional(),
408
+ transport: z3.enum(["http", "opcua"]).default("http"),
409
+ runtime: z3.strictObject({
410
+ entry: z3.string(),
411
+ target: z3.enum([
412
+ "bun-linux-x64",
413
+ "bun-linux-arm64",
414
+ "bun-darwin-x64",
415
+ "bun-darwin-arm64",
416
+ "bun-windows-x64"
417
+ ]).optional()
418
+ }).optional()
419
+ }).optional(),
420
+ compiler: z3.strictObject({
421
+ tsconfig: z3.string().default("tsconfig.json"),
422
+ programs: z3.record(z3.string(), z3.strictObject({ module: z3.string(), export: z3.string() }))
423
+ }).optional(),
424
+ tasks: z3.array(taskSchema2).nonempty().optional(),
425
+ build: configSchema.extend({ task: configSchema.shape.task.unwrap().optional() }).optional(),
426
+ codesys: z3.strictObject({
427
+ http: httpOptionsSchema.optional(),
428
+ programNames: z3.record(z3.string(), z3.string()).optional(),
429
+ deviceTree: z3.strictObject({ ethernet: ethernetSchema.optional() }).optional(),
430
+ controllers: z3.strictObject({
431
+ production: controllerTargetSchema.optional(),
432
+ development: controllerTargetSchema.optional()
433
+ }).optional()
434
+ }).optional(),
435
+ eds: z3.union([z3.string(), z3.array(z3.string())]).default("eds"),
436
+ devices: z3.record(z3.string(), hardwareDeviceSchema).default({}),
437
+ io: z3.record(z3.string(), ioBindingSchema).default({}),
438
+ dependencies: z3.record(z3.string(), dependencySchema).default({}),
439
+ typegen: typegenSchema.optional(),
440
+ monitor: monitorSchema.optional(),
441
+ hmi: hmiSchema.optional()
442
+ });
443
+ var buildTargetFor = (command) => ["run", "download", "online-change", "inspect"].includes(command) ? "development" : "production";
444
+ var controllerFor = (config, command) => {
445
+ const controller = config.codesys?.controllers?.[buildTargetFor(command)];
446
+ return controller && { ...controllerDevices[controller.target], version: controller.version };
447
+ };
448
+ var simulationConfig = (config) => ({
449
+ ...config,
450
+ eds: [],
451
+ devices: {},
452
+ io: {},
453
+ ...config.codesys && {
454
+ codesys: {
455
+ ...config.codesys,
456
+ deviceTree: undefined
457
+ }
458
+ }
459
+ });
460
+ function defineConfig(config) {
461
+ return config;
462
+ }
463
+ function rawBuildConfig(config) {
464
+ if (config.compiler)
465
+ throw new Error("Use the compiler build plan for TypeScript projects.");
466
+ if (!config.build)
467
+ throw new Error("Configure build settings.");
468
+ if (!config.tasks)
469
+ return config.build;
470
+ if (config.build.tasks || config.build.task !== undefined)
471
+ throw new Error("Configure the raw ST schedule in tasks or build.tasks/build.task, not both.");
472
+ return {
473
+ ...config.build,
474
+ tasks: cyclicTasksSchema.parse(config.tasks.map((task) => ({
475
+ name: task.name,
476
+ intervalNanoseconds: task.schedule.interval.nanoseconds,
477
+ priority: task.priority,
478
+ programs: task.programs
479
+ })))
480
+ };
481
+ }
482
+ function compilerConfig(config, io, buildTarget = "production") {
483
+ if (!config.compiler || !config.tasks)
484
+ throw new Error("This project uses raw Structured Text; no TypeScript compiler is configured.");
485
+ const { deviceTree: _deviceTree, controllers: _controllers, ...codesys } = config.codesys ?? {};
486
+ const value = {
487
+ name: config.name,
488
+ tsconfig: config.compiler.tsconfig,
489
+ programs: config.compiler.programs,
490
+ tasks: config.tasks,
491
+ target: {
492
+ kind: config.backend,
493
+ options: {
494
+ ...codesys,
495
+ publish: config.publish,
496
+ buildTarget,
497
+ io: Object.fromEntries(Object.entries(io).map(([name, binding]) => [
498
+ name,
499
+ {
500
+ kind: "direct",
501
+ ...binding,
502
+ ...mappedChannel(config, name, binding) && { mapped: true }
503
+ }
504
+ ])),
505
+ engineering: {
506
+ kind: "v3.5",
507
+ ...config.build ? { build: compilerBuildOptions(config.build) } : {}
508
+ }
509
+ }
510
+ }
511
+ };
512
+ const validated = validateConfig(value);
513
+ if (!validated.config)
514
+ throw new Error(validated.diagnostics.map((item) => item.message).join(`
515
+ `));
516
+ return validated.config;
517
+ }
518
+ function mappedChannel(config, name, binding) {
519
+ const source = config.io[name];
520
+ return config.codesys?.deviceTree !== undefined && source !== undefined && "device" in source && !binding.inverted && !binding.shared && /^%[IQ][XB]/.test(binding.address) && !/^ARRAY/i.test(binding.type ?? "");
521
+ }
522
+ function compilerBuildOptions(build) {
523
+ const {
524
+ sourceDir: _source,
525
+ entry: _entry,
526
+ outDir: _out,
527
+ task: _task,
528
+ tasks: _tasks,
529
+ ...settings
530
+ } = build;
531
+ return settings;
532
+ }
533
+ // packages/config/src/loader.ts
534
+ import { readFile } from "node:fs/promises";
535
+ import { dirname, resolve } from "node:path";
536
+ import { createJiti } from "jiti";
537
+ async function loadTsplcConfig(file = "tsplc.config.ts") {
538
+ const configFile = resolve(file);
539
+ await readFile(configFile);
540
+ const jiti = createJiti(import.meta.url, {
541
+ moduleCache: false,
542
+ fsCache: false,
543
+ interopDefault: false,
544
+ tryNative: false
545
+ });
546
+ const module = await jiti.import(configFile);
547
+ const config = tsplcConfigSchema.parse(module.default ?? module.config);
548
+ if (config.compiler && !config.tasks)
549
+ throw new Error("TypeScript programs require a tasks configuration.");
550
+ return { configFile, root: dirname(configFile), config };
551
+ }
552
+ export {
553
+ buildTargetFor,
554
+ buildTargetSchema,
555
+ compilerConfig,
556
+ controllerFor,
557
+ defineConfig,
558
+ definePlcConfig,
559
+ hmiSchema,
560
+ httpOptionsSchema,
561
+ loadTsplcConfig,
562
+ ms,
563
+ ns,
564
+ publicationSchema,
565
+ rawBuildConfig,
566
+ seconds,
567
+ simulationConfig,
568
+ tsplcConfigSchema,
569
+ typegenSchema,
570
+ validateConfig
571
+ };
572
+
573
+ //# debugId=35D15C1A44FCA22C64756E2164756E21
574
+ //# sourceMappingURL=index.js.map