@tsplc/build 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/LICENSE +21 -0
- package/README.md +6 -2
- package/dist/cli.js +1696 -0
- package/dist/cli.js.map +34 -0
- package/dist/index.js +1683 -0
- package/dist/index.js.map +31 -0
- package/dist/libraries.js +128 -0
- package/dist/libraries.js.map +10 -0
- package/docker/Dockerfile +173 -0
- package/docker/Dockerfile.dockerignore +18 -0
- package/docker/Dockerfile.source +15 -0
- package/docker/build-image +38 -0
- package/docker/codesys-build +5 -0
- package/docker/config.ts +8 -0
- package/docker/control-linux-sl/Dockerfile +38 -0
- package/docker/edge-gateway/Dockerfile +17 -0
- package/docker/entrypoint.sh +10 -0
- package/docker/install/NOTICE.md +21 -0
- package/docker/install/core.sh +36 -0
- package/docker/install/decode.c +12 -0
- package/docker/install/device/Runtime.ico +0 -0
- package/docker/install/device/Runtime.png +0 -0
- package/docker/install/device/codesyscontrol.devdesc.xml +1502 -0
- package/docker/install/extract.py +43 -0
- package/docker/install/helper-launcher.c +46 -0
- package/docker/install/install.sh +94 -0
- package/docker/install/prerequisites.sh +15 -0
- package/docker/install/verify.py +133 -0
- package/docker/install/verify.sh +34 -0
- package/docker/install/wine-ncrypt/COPYING.LIB +502 -0
- package/docker/install/wine-ncrypt/README.md +28 -0
- package/docker/install/wine-ncrypt/enable-oaep.py +34 -0
- package/docker/install/wine-ncrypt/main.c +619 -0
- package/docker/install/wine-ncrypt/oaep.patch +11 -0
- package/docker/install/wine-signal/README.md +22 -0
- package/docker/install/wine-signal/build.sh +10 -0
- package/docker/install/wine-signal/check.sh +34 -0
- package/docker/install/wine-signal/noop-i386.c +2 -0
- package/docker/install/wine-signal/signal-state.c +105 -0
- package/docker/install/wine-signal/tests/avx-registers.c +53 -0
- package/docker/install/wine-signal/tests/frame-and-handler.c +192 -0
- package/docker/install/wine-signal/tests/loader-i386.c +8 -0
- package/docker/install/wine-signal/tests/signal-return.c +47 -0
- package/docker/install/wine-signal/wine +4 -0
- package/docker/runner.ts +156 -0
- package/package.json +53 -4
- package/python/build.py +660 -0
- package/python/codesys_login.py +100 -0
- package/python/codesys_online.py +327 -0
- package/python/test_build.py +444 -0
- package/python/test_codesys_login.py +120 -0
- package/python/test_codesys_online.py +184 -0
- package/python/test_installer_packages.py +216 -0
- package/python/test_installer_verification.py +307 -0
- package/python/test_worker.py +142 -0
- package/python/worker.py +102 -0
- package/runtime/install.sh +74 -0
- package/src/__tests__/fixtures/xml/fb-simple.xml +40 -0
- package/src/__tests__/fixtures/xml/fb-state-machine.xml +86 -0
- package/src/__tests__/fixtures/xml/prg-cyclic.xml +44 -0
- package/src/artifacts.ts +77 -0
- package/src/build.ts +87 -0
- package/src/cli.ts +116 -0
- package/src/config.ts +12 -0
- package/src/controller-online.ts +297 -0
- package/src/controller-session.ts +298 -0
- package/src/diagnostics.ts +68 -0
- package/src/docker-build.ts +163 -0
- package/src/docker-context.ts +35 -0
- package/src/docker-run.ts +103 -0
- package/src/host/codesys-command.ts +45 -0
- package/src/host/codesys-host.ts +145 -0
- package/src/host/codesys-worker.ts +348 -0
- package/src/host/windows-path.ts +73 -0
- package/src/index.ts +43 -0
- package/src/io.ts +127 -0
- package/src/libraries.ts +166 -0
- package/src/package-path.ts +5 -0
- package/src/run.ts +133 -0
- package/src/runtime-status.ts +21 -0
- package/src/sources.ts +248 -0
- package/src/st/declarations.ts +229 -0
- package/src/st/lexer.ts +125 -0
- package/src/st/parse.ts +202 -0
- package/src/st/reader.ts +50 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/cli.ts", "../src/artifacts.ts", "../src/config.ts", "../src/docker-build.ts", "../src/docker-context.ts", "../src/package-path.ts", "../src/diagnostics.ts", "../src/docker-run.ts", "../src/host/codesys-worker.ts", "../src/host/codesys-command.ts", "../src/host/codesys-host.ts", "../src/host/windows-path.ts", "../src/st/parse.ts", "../src/st/declarations.ts", "../src/st/lexer.ts", "../src/st/reader.ts", "../src/io.ts", "../src/build.ts", "../src/config.ts", "../src/controller-online.ts", "../src/docker-build.ts", "../src/libraries.ts", "../src/run.ts", "../src/runtime-status.ts", "../src/sources.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"#!/usr/bin/env bun\nimport { parseArgs } from \"node:util\";\nimport { deviceTree } from \"@tsplc/typegen\";\nimport { loadHardware, resolveIo } from \"@tsplc/typegen/hardware\";\nimport { controllerFor, loadTsplcConfig, rawBuildConfig } from \"@tsplc/config\";\nimport { buildProject } from \"./build.ts\";\nimport { resolveConfig } from \"./config.ts\";\nimport { inspectController, updateController } from \"./controller-online.ts\";\nimport { configureDocker, configureRuntime } from \"./docker-build.ts\";\nimport { installLibraries } from \"./libraries.ts\";\nimport { runProject } from \"./run.ts\";\nimport { loadSources } from \"./sources.ts\";\n\nasync function main() {\n const { values, positionals } = parseArgs({\n allowPositionals: true,\n options: {\n config: { type: \"string\" },\n help: { type: \"boolean\", short: \"h\" },\n read: { type: \"string\", multiple: true },\n \"initialize-user\": { type: \"boolean\" },\n \"frozen-lockfile\": { type: \"boolean\" },\n runtime: { type: \"boolean\" },\n },\n });\n const command = positionals[0];\n const commands = new Set([\n \"configure\",\n \"install\",\n \"check\",\n \"build\",\n \"run\",\n \"download\",\n \"online-change\",\n \"inspect\",\n ]);\n if (positionals.length > 1) throw new Error(\"Specify one command.\");\n if (!command || values.help) {\n console.log(\n \"tsplc-build configure|install|check|build|run|download|online-change|inspect [--config tsplc.config.ts] [--read symbol] [--runtime]\",\n );\n return;\n }\n if (!commands.has(command)) throw new Error(`Unknown command ${command}.`);\n if (values.runtime && command !== \"configure\")\n throw new Error(\"--runtime applies only to configure.\");\n if (command === \"configure\") {\n await (values.runtime ? configureRuntime() : configureDocker());\n return;\n }\n const { config, configFile, root } = await loadTsplcConfig(values.config);\n if (command === \"install\") {\n const libraries = await installLibraries(config.dependencies, root, {\n frozen: values[\"frozen-lockfile\"],\n });\n console.log(`Installed ${libraries.length} CODESYS libraries.`);\n return;\n }\n if (!config.build) throw new Error(\"Configure build options in tsplc.config.ts.\");\n if (command === \"inspect\") {\n // Inspection only needs connection/baseline settings; it remains usable\n // without sources, EDS descriptors or installed library payloads.\n console.log(\n JSON.stringify(\n await inspectController(\n resolveConfig(\n { ...config.build, controller: controllerFor(config, command) },\n configFile,\n ),\n values.read,\n ),\n null,\n 2,\n ),\n );\n return;\n }\n if (config.compiler)\n throw new Error(\"Use tsplc for TypeScript projects. tsplc-build accepts raw Structured Text.\");\n const build = rawBuildConfig(config);\n const hardware = await loadHardware(config, root);\n const io = resolveIo(config, hardware);\n if (command === \"check\") {\n const sources = await loadSources(resolveConfig({ ...build, io }, configFile));\n console.log(`Validated ${sources.objects.length} Structured Text objects.`);\n return;\n }\n const libraries = await installLibraries(config.dependencies, root, {\n frozen: values[\"frozen-lockfile\"],\n });\n const settings = resolveConfig(\n {\n ...build,\n libraries,\n io,\n deviceTree: await deviceTree(config, hardware),\n controller: controllerFor(config, command),\n },\n configFile,\n );\n if (command === \"build\") await buildProject(settings);\n else if (command === \"run\") {\n await buildProject(settings);\n await runProject(settings, config.name);\n } else if (command === \"download\" || command === \"online-change\")\n await updateController(settings, command, {\n initializeUser: values[\"initialize-user\"],\n read: values.read,\n });\n}\ntry {\n await main();\n} catch (cause) {\n console.error(cause instanceof Error ? cause.message : String(cause));\n process.exitCode = 1;\n}\n",
|
|
6
|
+
"import { copyFile, cp, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { z } from \"zod\";\nimport { cyclicTasksSchema } from \"./config\";\n\nexport const buildFiles = {\n project: \"Application.project\",\n output: \"runtime/Application.app\",\n checksum: \"runtime/Application.crc\",\n receipt: \"build.json\",\n // Normalized EDS files of a generated device tree, imported by the worker.\n devices: \"eds\",\n // With a generated device tree: the project plus the descriptions an IDE needs.\n archive: \"Application.projectarchive\",\n} as const;\n\nconst receiptSchema = z.object({\n mode: z.literal(\"build\"),\n application: z.string().regex(/^[A-Za-z_][A-Za-z_0-9]*$/),\n tasks: cyclicTasksSchema.optional(),\n});\n\n/** A receipt is published last, after every artifact has been checked and replaced. */\nexport const readBuild = async (directory: string) => {\n const receipt = receiptSchema.safeParse(\n JSON.parse(await readFile(resolve(directory, buildFiles.receipt), \"utf8\")),\n );\n if (!receipt.success) {\n throw new Error(\"CODESYS did not produce a valid build receipt\", {\n cause: receipt.error,\n });\n }\n for (const file of [buildFiles.project, buildFiles.output, buildFiles.checksum]) {\n const artifact = await stat(resolve(directory, file));\n if (!artifact.isFile() || artifact.size === 0) {\n throw new Error(`CODESYS produced an empty artifact: ${file}`);\n }\n }\n return {\n ...receipt.data,\n directory,\n project: resolve(directory, buildFiles.project),\n output: resolve(directory, buildFiles.output),\n checksum: resolve(directory, buildFiles.checksum),\n };\n};\n\n/** Publish a verified IDE build, with the completion receipt written last. */\nexport const publishBuild = async (\n compiled: Awaited<ReturnType<typeof readBuild>>,\n outDir: string,\n) => {\n await copyFile(compiled.project, resolve(outDir, buildFiles.project));\n await rm(resolve(outDir, \"runtime\"), { recursive: true, force: true });\n await rename(resolve(compiled.directory, \"runtime\"), resolve(outDir, \"runtime\"));\n await rm(resolve(outDir, buildFiles.archive), { force: true });\n await cp(\n resolve(compiled.directory, buildFiles.archive),\n resolve(outDir, buildFiles.archive),\n ).catch((cause: unknown) => {\n if (!(cause && typeof cause === \"object\" && \"code\" in cause && cause.code === \"ENOENT\"))\n throw cause;\n });\n await writeFile(\n resolve(outDir, buildFiles.receipt),\n JSON.stringify(\n {\n mode: \"build\",\n application: compiled.application,\n ...(compiled.tasks && { tasks: compiled.tasks }),\n },\n null,\n 2,\n ),\n );\n return readBuild(outDir);\n};\n",
|
|
7
|
+
"export {\n configSchema,\n controllerSchema,\n cyclicTasksSchema,\n dockerImage,\n defineBuildConfig as defineConfig,\n resolveConfig,\n loadConfig,\n type CodesysBuildConfig,\n type ResolvedConfig,\n type CyclicTask,\n} from \"@tsplc/config/build\";\n",
|
|
8
|
+
"import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { cp, mkdir, mkdtemp, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { readBuild } from \"./artifacts\";\nimport { dockerImage, type ResolvedConfig } from \"./config\";\nimport { prepareDockerContext } from \"./docker-context.ts\";\nimport { buildFailureFile, buildFailureSchema, CodesysCompilerError } from \"./diagnostics.ts\";\nimport { prepareContainerRun, runDocker } from \"./docker-run.ts\";\nimport { packageDirectory } from \"./package-path.ts\";\n\nconst execute = promisify(execFile);\n\n/** Install the IDE and its prerequisites in the Docker builder image. */\nexport const configureDocker = async () => {\n const image = dockerImage;\n const { stdout } = await execute(\n \"docker\",\n [\"info\", \"--format\", \"{{.OSType}}/{{.Architecture}}\"],\n { timeout: 30_000 },\n ).catch((cause: unknown) => {\n throw new Error(\"Cannot connect to Docker. Install and start Docker Desktop or Docker Engine\", {\n cause,\n });\n });\n const architecture = stdout.trim();\n const arm = architecture === \"linux/aarch64\" || architecture === \"linux/arm64\";\n if (!arm && architecture !== \"linux/x86_64\" && architecture !== \"linux/amd64\") {\n throw new Error(\"The builder requires a Linux Docker server on ARM64 or AMD64\");\n }\n const context = await mkdtemp(resolve(tmpdir(), \"codesys-installer-\"));\n let buildContext: string | undefined;\n try {\n buildContext = await prepareDockerContext();\n const cache = resolve(context, \"winetricks\");\n await mkdir(cache);\n if (process.env[\"CODESYS_WINETRICKS_CACHE\"]) {\n await cp(process.env[\"CODESYS_WINETRICKS_CACHE\"], cache, {\n recursive: true,\n });\n }\n console.log(\n `Preparing Docker builder (${image}). Downloading and installing CODESYS 3.5.22.30 and prerequisites.`,\n );\n await runDocker(\n [\n \"build\",\n \"--platform\",\n \"linux/amd64\",\n \"--build-arg\",\n `SETUP_BASE=${arm ? \"arm-setup\" : \"base\"}`,\n \"--build-arg\",\n `SETUP_PLATFORM=${arm ? \"linux/arm64\" : \"linux/amd64\"}`,\n \"--build-arg\",\n \"INSTALLER_SOURCE=installer-download\",\n \"--progress\",\n \"plain\",\n \"--build-context\",\n `installer=${context}`,\n \"-f\",\n resolve(buildContext, \"docker/Dockerfile\"),\n \"-t\",\n image,\n buildContext,\n ],\n (status) =>\n `Docker configuration failed (${status}). Review the image-build output and run tsplc configure again`,\n );\n return image;\n } finally {\n await Promise.all([\n rm(context, { recursive: true, force: true }),\n ...(buildContext ? [rm(buildContext, { recursive: true, force: true })] : []),\n ]);\n }\n};\n\nexport const runtimeImage = \"tsplc-control-linux-sl:4.22.0.0\";\n\n/** Build the local CODESYS Control for Linux SL runtime, the same device as a production build. */\nexport const configureRuntime = async () => {\n const context = resolve(packageDirectory, \"docker/control-linux-sl\");\n console.log(`Preparing the local PLC runtime (${runtimeImage}).`);\n await runDocker(\n [\"build\", \"--platform\", \"linux/amd64\", \"--progress\", \"plain\", \"-t\", runtimeImage, context],\n (status) => `Runtime image build failed (${status}). Review the image-build output`,\n );\n return runtimeImage;\n};\n\nexport const gatewayImage = \"tsplc-edge-gateway:4.22.0.0\";\n\n/** Build the CODESYS Edge Gateway that builder containers reach a plant controller through. */\nexport const configureGateway = async () => {\n const context = resolve(packageDirectory, \"docker/edge-gateway\");\n console.log(`Preparing the CODESYS gateway (${gatewayImage}).`);\n await runDocker(\n [\"build\", \"--platform\", \"linux/amd64\", \"--progress\", \"plain\", \"-t\", gatewayImage, context],\n (status) => `Gateway image build failed (${status}). Review the image-build output`,\n );\n return gatewayImage;\n};\n\nexport const buildInDocker = async (config: ResolvedConfig, image: string) => {\n const requestDirectory = await mkdtemp(resolve(tmpdir(), \"codesys-docker-\"));\n try {\n const operationId = randomUUID();\n await mkdir(config.outDir, { recursive: true });\n const failurePath = resolve(config.outDir, buildFailureFile);\n await rm(failurePath, { force: true });\n const args = [\n \"run\",\n \"--rm\",\n ...(await prepareContainerRun(config, requestDirectory, { network: \"none\", sources: true })),\n image,\n \"--request\",\n \"/input/config.json\",\n \"--operation-id\",\n operationId,\n ];\n console.log(`Building with Docker (${image})`);\n try {\n await runDocker(\n args,\n (status) =>\n `Docker build failed (${status}). Run tsplc configure if the image is missing; inspect ${config.outDir}/.codesys/docker for compiler logs`,\n );\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n const failure = await readFile(failurePath, \"utf8\")\n .then((text) => buildFailureSchema.parse(JSON.parse(text)))\n .catch((error: unknown) => {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return;\n throw new AggregateError(\n [cause, error],\n `${message}. Invalid CODESYS failure metadata (${failurePath})`,\n { cause: error },\n );\n });\n if (!failure) throw cause;\n if (failure.operationId !== operationId)\n throw new Error(\n `${message}. CODESYS failure metadata belongs to a different Docker build`,\n {\n cause,\n },\n );\n if (cause instanceof Error) {\n // The mapper keeps ordinary error messages as notes, while vendor\n // diagnostics supply their own text. Preserve shutdown context there.\n cause.message = `${message}\\n${failure.message}`;\n if (failure.diagnostics.length)\n cause.cause = new CodesysCompilerError(failure.message, failure.diagnostics);\n }\n throw cause;\n }\n return await readBuild(config.outDir);\n } finally {\n await rm(requestDirectory, { recursive: true, force: true });\n }\n};\n",
|
|
9
|
+
"import { cp, mkdir, mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { packageDirectory } from \"./package-path.ts\";\n\nexport async function prepareDockerContext() {\n const context = await mkdtemp(resolve(tmpdir(), \"tsplc-docker-\"));\n try {\n for (const directory of [\"src\", \"python\", \"docker\", \"runtime\"])\n await cp(resolve(packageDirectory, directory), resolve(context, directory), {\n recursive: true,\n });\n const configRoot = resolve(\n dirname(createRequire(import.meta.url).resolve(\"@tsplc/config/build\")),\n \"..\",\n );\n await mkdir(resolve(context, \"shared-config\"));\n await cp(resolve(configRoot, \"src\"), resolve(context, \"shared-config/src\"), {\n recursive: true,\n });\n await cp(resolve(configRoot, \"templates\"), resolve(context, \"shared-config/templates\"), {\n recursive: true,\n });\n await cp(resolve(configRoot, \"package.json\"), resolve(context, \"shared-config/package.json\"));\n await writeFile(\n resolve(context, \"package.json\"),\n JSON.stringify({ type: \"module\", dependencies: { zod: \"4.3.6\", jiti: \"2.7.0\" } }),\n );\n return context;\n } catch (cause) {\n await rm(context, { recursive: true, force: true });\n throw cause;\n }\n}\n",
|
|
10
|
+
"import { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Both source modules and published bundles live one directory below the package root.\nexport const packageDirectory = resolve(fileURLToPath(new URL(\"..\", import.meta.url)));\n",
|
|
11
|
+
"import { z } from \"zod\";\n\nexport const compilerDiagnosticSchema = z\n .object({\n category: z.string(),\n text: z.string(),\n severity: z.string().nullable(),\n project: z.string().nullable(),\n object: z\n .object({\n name: z.string(),\n guid: z.string(),\n path: z.array(z.string()),\n /** Verified against this message project's active application GUID. */\n isApplicationChild: z.boolean().nullable(),\n })\n .passthrough()\n .nullable(),\n /** Opaque vendor position. It must not be decoded as a line or column. */\n position: z.string().nullable(),\n positionText: z.string().nullable(),\n positionOffset: z.int().nullable(),\n length: z.int().nullable(),\n prefix: z.string().nullable(),\n number: z.int().nullable(),\n })\n .passthrough();\n\nexport type CodesysCompilerDiagnostic = z.infer<typeof compilerDiagnosticSchema>;\n\n/** Preserves vendor diagnostics as the cause of a buildProject failure. */\nexport class CodesysCompilerError extends Error {\n constructor(\n message: string,\n readonly diagnostics: readonly CodesysCompilerDiagnostic[],\n ) {\n super(message);\n this.name = \"CodesysCompilerError\";\n }\n}\n\n// A failed container job publishes diagnostics separately from its successful build receipt.\nexport const buildFailureFile = \".codesys/docker/failure.json\";\n/** Why the last download, online change or inspection failed, for the host to report. */\nexport const controllerFailureFile = \".codesys/controller/failure.txt\";\nexport const buildFailureSchema = z.strictObject({\n operationId: z.uuid(),\n message: z.string(),\n diagnostics: z.array(compilerDiagnosticSchema),\n});\n\n/** Keep the primary compiler location and the shutdown context across the Docker boundary. */\nexport function describeBuildFailure(cause: unknown) {\n const messages: string[] = [];\n let diagnostics: readonly CodesysCompilerDiagnostic[] = [];\n let current = cause;\n while (current instanceof Error) {\n messages.push(current.message);\n if (current instanceof AggregateError) {\n // withWorkerShutdown puts the primary failure in cause and secondary failures in errors.\n for (const secondary of current.errors.slice(1))\n messages.push(secondary instanceof Error ? secondary.message : String(secondary));\n }\n if (current instanceof CodesysCompilerError) diagnostics = current.diagnostics;\n current = current.cause;\n }\n return { message: messages.length ? messages.join(\"\\n\") : String(cause), diagnostics };\n}\n",
|
|
12
|
+
"import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { basename, posix, relative, resolve, sep } from \"node:path\";\nimport type { ResolvedConfig } from \"./config.ts\";\n\n/** Run a Docker client command attached to this terminal and forward interruption to it. */\nexport const runDocker = (args: string[], failure: (status: string | number | null) => string) =>\n new Promise<void>((accept, reject) => {\n const child = spawn(\"docker\", args, {\n stdio: [\"inherit\", process.env[\"TSPLC_LOG_STDERR\"] === \"1\" ? 2 : \"inherit\", \"inherit\"],\n });\n const interrupt = () => child.kill(\"SIGINT\");\n const terminate = () => child.kill(\"SIGTERM\");\n process.on(\"SIGINT\", interrupt);\n process.on(\"SIGTERM\", terminate);\n const cleanup = () => {\n process.off(\"SIGINT\", interrupt);\n process.off(\"SIGTERM\", terminate);\n };\n child.once(\"error\", (cause) => {\n cleanup();\n reject(\n new Error(\"Cannot start Docker. Install and start Docker Desktop or Docker Engine\", {\n cause,\n }),\n );\n });\n child.once(\"exit\", (code, signal) => {\n cleanup();\n if (code === 0) {\n accept();\n } else {\n reject(new Error(failure(signal ?? code)));\n }\n });\n });\n\nconst bindMount = (source: string, target: string, readonly = false) =>\n `type=bind,\"source=${source.replaceAll('\"', '\"\"')}\",target=${target}${readonly ? \",readonly\" : \"\"}`;\n\nasync function mountLibraries(libraries: ResolvedConfig[\"libraries\"], directory: string) {\n if (!libraries?.length) return undefined;\n await mkdir(resolve(directory, \"libraries\"), { recursive: true });\n return Promise.all(\n libraries.map(async (library) => {\n const data = await readFile(library.path);\n if (createHash(\"sha256\").update(data).digest(\"hex\") !== library.sha256)\n throw new Error(`Library changed after installation: ${library.title}`);\n const filename = `${library.sha256}-${basename(library.path)}`;\n await writeFile(resolve(directory, \"libraries\", filename), data);\n return { ...library, path: `/input/libraries/${filename}` };\n }),\n );\n}\n\n/**\n * Write the builder container's request and return the `docker run` options that precede\n * the image; the caller chooses `--rm` or `--detach`. The request names only container paths;\n * host paths enter through these mounts, and host-only Docker, CODESYS and runtime settings\n * stay outside.\n */\nexport const prepareContainerRun = async (\n config: ResolvedConfig,\n requestDirectory: string,\n options: { network: string; environment?: string[]; sources: boolean },\n) => {\n await writeFile(\n resolve(requestDirectory, \"config.json\"),\n JSON.stringify({\n ...config,\n libraries: options.sources ? await mountLibraries(config.libraries, requestDirectory) : [],\n configFile: undefined,\n docker: undefined,\n codesys: undefined,\n sourceDir: \"/sources\",\n entry: posix.resolve(\n \"/sources\",\n relative(config.sourceDir, config.entry).split(sep).join(\"/\"),\n ),\n template: \"/template.project\",\n outDir: \"/output\",\n runtime: undefined,\n }),\n );\n return [\n \"--init\",\n ...(config.docker?.cpuSet ? [\"--cpuset-cpus\", config.docker.cpuSet] : []),\n \"--network\",\n options.network,\n ...(process.getuid && process.getgid\n ? [\"--user\", `${process.getuid()}:${process.getgid()}`]\n : []),\n ...(options.environment ?? []).flatMap((name) => [\"--env\", name]),\n \"--mount\",\n bindMount(requestDirectory, \"/input\", true),\n ...(options.sources ? [\"--mount\", bindMount(config.sourceDir, \"/sources\", true)] : []),\n \"--mount\",\n bindMount(config.template, \"/template.project\", true),\n \"--mount\",\n bindMount(config.outDir, \"/output\"),\n ];\n};\n",
|
|
13
|
+
"// Engineering CLI lifecycle and diagnostics.\nimport { createHash, randomUUID } from \"node:crypto\";\nimport {\n access,\n copyFile,\n mkdir,\n open,\n readFile,\n rename,\n rm,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { z } from \"zod\";\nimport type { ResolvedConfig } from \"../config\";\nimport { CodesysCompilerError, compilerDiagnosticSchema } from \"../diagnostics\";\nimport { packageDirectory } from \"../package-path\";\nimport { codesysCommand, getHostCommand } from \"./codesys-command\";\nimport { createCodesysHost } from \"./codesys-host\";\n\nconst pythonDirectory = resolve(packageDirectory, \"python\");\n\nconst sessionSchema = z.object({\n directory: z.string(),\n fingerprint: z.string(),\n pid: z.int().positive(),\n});\n\ntype Session = z.infer<typeof sessionSchema>;\n\ntype WorkerCommand =\n | { action: \"build\" | \"online\" | \"ping\" | \"stop\" }\n | { action: \"login\"; arguments: Record<string, unknown> };\n\nconst hasCode = (error: unknown, code: string) =>\n error instanceof Error && \"code\" in error && error.code === code;\n\nconst isProcessAlive = (pid: number) => {\n try {\n // Signal 0 checks process existence and permissions without killing it.\n // Only ESRCH means it is gone; permission errors must still propagate.\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if (hasCode(error, \"ESRCH\")) {\n return false;\n }\n throw error;\n }\n};\n\nconst readJson = async (path: string): Promise<unknown> => {\n try {\n return JSON.parse(await readFile(path, \"utf8\"));\n } catch (error) {\n if (hasCode(error, \"ENOENT\")) {\n return undefined;\n }\n throw error;\n }\n};\n\nexport const writeJson = async (path: string, value: unknown) => {\n // Readers may poll while we write. A temporary file in the same directory\n // lets rename publish the complete JSON atomically, without exposing partial data.\n const temporary = `${path}.${randomUUID()}.tmp`;\n await writeFile(temporary, JSON.stringify(value, null, 2));\n await rename(temporary, path);\n};\n\n/** Serializes startup and builds across CLI processes, including separate terminals. */\nexport const withWorkerLock = async <T>(\n config: Pick<ResolvedConfig, \"outDir\" | \"timeouts\">,\n run: () => Promise<T>,\n) => {\n await mkdir(resolve(config.outDir, \".codesys\"), { recursive: true });\n const path = resolve(config.outDir, \".codesys/command.lock\");\n const deadline = Date.now() + config.timeouts.build + config.timeouts.startup;\n while (true) {\n const lock = await open(path, \"wx\").catch((error: unknown) => {\n if (hasCode(error, \"EEXIST\")) {\n return;\n }\n throw error;\n });\n\n if (lock) {\n try {\n await lock.writeFile(String(process.pid));\n return await run();\n } finally {\n await lock.close();\n await unlink(path);\n }\n }\n\n const owner = Number(\n await readFile(path, \"utf8\").catch((error: unknown) => {\n if (hasCode(error, \"ENOENT\")) {\n return \"\";\n }\n throw error;\n }),\n );\n if (owner > 0 && !isProcessAlive(owner)) {\n // Do not race another client by deleting a lock that it may have replaced.\n throw new Error(`An interrupted command left ${path}. Remove that lock file and retry.`);\n }\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for another CODESYS command (${path})`);\n }\n await delay(200);\n }\n};\n\n/** The caller holds withWorkerLock throughout a command, so the mailbox has one writer. */\nexport const createCodesysWorker = (config: ResolvedConfig) => {\n const host = createCodesysHost(config);\n const statePath = resolve(config.outDir, \".codesys/session.json\");\n const verifiedProcesses = new Set<number>();\n\n const readSession = async (): Promise<Session | undefined> => {\n const value = await readJson(statePath);\n if (value === undefined) {\n return undefined;\n }\n const session = sessionSchema.safeParse(value);\n if (!session.success) {\n throw new Error(`Invalid CODESYS session file: ${statePath}`, {\n cause: session.error,\n });\n }\n return session.data;\n };\n\n const terminate = async (session: Session) => {\n if (isProcessAlive(session.pid)) {\n await host.terminate(session.pid).catch((error: unknown) => {\n if (isProcessAlive(session.pid)) {\n throw error;\n }\n });\n }\n // Let the launcher reap its child before another error handler or CLI\n // checks this PID. Sending a second group kill can otherwise race exit.\n const deadline = Date.now() + config.timeouts.terminate;\n while (isProcessAlive(session.pid)) {\n if (Date.now() >= deadline) {\n throw new Error(\"CODESYS launcher did not exit after termination\");\n }\n await delay(50);\n }\n };\n\n const request = async (session: Session, command: WorkerCommand, timeoutMs: number) => {\n const id = randomUUID();\n const reply = resolve(session.directory, `${id}.json`);\n await writeJson(resolve(session.directory, \"request.json\"), {\n ...command,\n id,\n });\n const deadline = Date.now() + timeoutMs;\n while (true) {\n const result = await readJson(reply);\n if (result !== undefined) {\n await unlink(reply);\n const response = z\n .object({\n error: z.string().optional(),\n diagnostics: z.array(compilerDiagnosticSchema).optional(),\n id: z.literal(id),\n ok: z.boolean(),\n result: z.unknown(),\n })\n .safeParse(result);\n if (!response.success) {\n throw new Error(\"CODESYS returned an invalid worker response\", {\n cause: response.error,\n });\n }\n verifiedProcesses.add(session.pid);\n if (!response.data.ok) {\n const message = response.data.error ?? \"CODESYS build failed\";\n if (response.data.diagnostics) {\n throw new CodesysCompilerError(message, response.data.diagnostics);\n }\n throw new Error(message);\n }\n return response.data.result;\n }\n if (!isProcessAlive(session.pid)) {\n throw new Error(\n `CODESYS exited before completing ${command.action}. See ${session.directory}/codesys.log`,\n );\n }\n if (Date.now() >= deadline) {\n // A saved PID can belong to another process after a reboot. Only kill\n // a process we launched or whose worker answered in this invocation.\n if (!verifiedProcesses.has(session.pid)) {\n throw new Error(\n `CODESYS ${command.action} timed out without a worker response. Close the dedicated IDE if it is still running, then retry. Log: ${session.directory}/codesys.log`,\n );\n }\n await terminate(session);\n throw new Error(\n `CODESYS ${command.action} timed out after ${timeoutMs} ms; the worker was stopped. See ${session.directory}/codesys.log`,\n );\n }\n await delay(200);\n }\n };\n\n const launch = async () => {\n await access(config.codesys.executable);\n const fingerprint = createHash(\"sha256\")\n .update(\n JSON.stringify({\n builder: await readFile(resolve(pythonDirectory, \"build.py\"), \"utf8\"),\n online: await readFile(resolve(pythonDirectory, \"codesys_online.py\"), \"utf8\"),\n login: await readFile(resolve(pythonDirectory, \"codesys_login.py\"), \"utf8\"),\n command: codesysCommand,\n codesys: config.codesys,\n launcher: getHostCommand(config.codesys),\n worker: await readFile(resolve(pythonDirectory, \"worker.py\"), \"utf8\"),\n }),\n )\n .digest(\"hex\");\n const previous = await readSession();\n if (previous && isProcessAlive(previous.pid)) {\n if (previous.fingerprint !== fingerprint) {\n throw new Error(\n \"CODESYS settings or worker scripts changed. Run stop-worker, then launch-worker to reload them.\",\n );\n }\n await request(previous, { action: \"ping\" }, config.timeouts.startup);\n console.log(\n `Reusing CODESYS worker (${previous.pid}). Log: ${previous.directory}/codesys.log`,\n );\n return previous;\n }\n\n const directory = resolve(config.outDir, \".codesys/worker\");\n await rm(directory, { recursive: true, force: true });\n await mkdir(directory, { recursive: true });\n await copyFile(resolve(pythonDirectory, \"build.py\"), resolve(directory, \"build.py\"));\n await copyFile(resolve(pythonDirectory, \"worker.py\"), resolve(directory, \"worker.py\"));\n for (const script of [\"codesys_online.py\", \"codesys_login.py\"]) {\n await copyFile(resolve(pythonDirectory, script), resolve(directory, script));\n }\n console.log(`Starting CODESYS. Log: ${directory}/codesys.log`);\n const pid = await host.startWorker(directory);\n const session = { directory, fingerprint, pid };\n verifiedProcesses.add(pid);\n try {\n await writeJson(statePath, session);\n await request(session, { action: \"ping\" }, config.timeouts.startup);\n } catch (error) {\n await terminate(session);\n throw error;\n }\n console.log(`CODESYS worker ready (${session.pid})`);\n return session;\n };\n\n const checkExit = async (session: Session) => {\n const status = await host.exitStatus(session.directory, session.pid);\n if (!status) {\n throw new Error(\n `CODESYS launcher stopped but its exit status is unavailable. See ${session.directory}/codesys.log`,\n );\n }\n if (status.code !== 0 || status.signal !== null) {\n throw new Error(\n `CODESYS launcher exited with ${status.signal ?? status.code ?? \"unknown status\"}. See ${session.directory}/codesys.log`,\n );\n }\n };\n\n const stop = async () => {\n const session = await readSession();\n if (!session) {\n console.log(\"CODESYS worker is already stopped\");\n return;\n }\n if (!isProcessAlive(session.pid)) {\n await checkExit(session);\n console.log(\"CODESYS worker is already stopped\");\n return;\n }\n await request(session, { action: \"stop\" }, config.timeouts.stop);\n const deadline = Date.now() + config.timeouts.stop;\n while (isProcessAlive(session.pid)) {\n if (Date.now() >= deadline) {\n const message = `CODESYS stop timed out after ${config.timeouts.stop} ms. See ${session.directory}/codesys.log`;\n try {\n await terminate(session);\n } catch (cause) {\n throw new Error(`${message}; the worker could not be terminated`, { cause });\n }\n throw new Error(`${message}; the worker required forced termination`);\n }\n await delay(200);\n }\n await checkExit(session);\n console.log(\"CODESYS worker stopped\");\n };\n\n return { launch, request, stop };\n};\n\n/** Container jobs own a temporary worker; always stop it before returning a result. */\nexport const withWorkerShutdown = async <T>(\n config: ResolvedConfig,\n worker: Pick<ReturnType<typeof createCodesysWorker>, \"stop\">,\n operation: () => Promise<T>,\n) => {\n const stop = async () => {\n try {\n await withWorkerLock(config, () => worker.stop());\n } finally {\n await rm(resolve(config.outDir, \".codesys/session.json\"), { force: true });\n }\n };\n return Promise.resolve()\n .then(operation)\n .then(\n async (result) => {\n await stop();\n return result;\n },\n async (failure: unknown) => {\n await stop().catch((shutdownFailure: unknown) => {\n // Diagnostic mapping follows cause; keep the operation there and\n // expose its shutdown failure alongside it in errors.\n throw new AggregateError(\n [failure, shutdownFailure],\n \"CODESYS operation and worker shutdown failed\",\n {\n cause: failure,\n },\n );\n });\n throw failure;\n },\n );\n};\n",
|
|
14
|
+
"export { commandArgumentSchema } from \"@tsplc/config/build\";\nimport type { ResolvedConfig } from \"../config\";\n\nexport const codesysCommandFilename = \"run.cmd\";\n\n// Keep arguments in the Windows command line: Wine's direct launcher loses the\n// quoting CODESYS needs around profile names containing spaces.\nexport const codesysCommand = [\n \"@echo off\",\n \"setlocal DisableDelayedExpansion\",\n '\"%CODESYS_BUILD_EXE%\" --profile=\"%CODESYS_BUILD_PROFILE%\" --noUI --runscript=\"%CODESYS_BUILD_SCRIPT%\"',\n 'set \"CODESYS_BUILD_STATUS=%errorlevel%\"',\n 'if not \"%CODESYS_BUILD_STATUS%\"==\"0\" echo CODESYS Windows exit status: %CODESYS_BUILD_STATUS%',\n \"exit /b %CODESYS_BUILD_STATUS%\",\n \"\",\n].join(\"\\r\\n\");\n\nexport const getHostCommand = (\n config: Pick<ResolvedConfig[\"codesys\"], \"commandProcessor\" | \"wine\">,\n platform: NodeJS.Platform = process.platform,\n) => {\n if (platform === \"win32\") {\n return {\n args: [\"/d\", \"/c\", codesysCommandFilename],\n executable: config.commandProcessor,\n };\n }\n const wine = config.wine?.binary ?? \"wine\";\n const args = [\"cmd\", \"/d\", \"/c\", codesysCommandFilename];\n // --noUI suppresses the IDE, but CODESYS can still allocate a Wine console.\n // A private PTY makes Wine use its Unix console instead of a desktop window.\n return {\n args:\n platform === \"darwin\"\n ? [\"-q\", \"/dev/null\", wine, ...args]\n : [\n \"-q\",\n \"-e\",\n \"-c\",\n [wine, ...args].map((argument) => `'${argument.replaceAll(\"'\", \"'\\\\''\")}'`).join(\" \"),\n \"/dev/null\",\n ],\n executable: \"script\",\n };\n};\n",
|
|
15
|
+
"import { execFile, spawn } from \"node:child_process\";\nimport { appendFileSync, constants, renameSync, writeFileSync } from \"node:fs\";\nimport { access, open, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { delimiter, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { z } from \"zod\";\nimport type { ResolvedConfig } from \"../config\";\nimport { codesysCommand, codesysCommandFilename, getHostCommand } from \"./codesys-command\";\nimport { toWindowsPath } from \"./windows-path\";\n\nconst execute = promisify(execFile);\nconst exitSchema = z.object({\n pid: z.int().positive(),\n code: z.int().nullable(),\n signal: z.string().nullable(),\n});\n\nexport const createCodesysHost = (config: ResolvedConfig) => {\n const native = process.platform === \"win32\";\n const { codesys, timeouts } = config;\n const hostEnv = {\n // Child processes inherit OS settings such as PATH and DISPLAY.\n ...process.env,\n WINEPREFIX: codesys.wine?.prefix,\n WINEDEBUG: codesys.wine?.debug,\n CODESYS_BUILD_NATIVE_EXIT: String(codesys.wine?.nativeExit ?? false),\n };\n\n /** Start the headless worker script; its launcher outlives this CLI process. */\n const startWorker = async (directory: string) => {\n if (!native) {\n await execute(codesys.wine?.binary ?? \"wine\", [\"--version\"], {\n env: hostEnv,\n timeout: timeouts.hostCommand,\n }).catch((cause: unknown) => {\n throw new Error(\"Wine is missing. Install Wine; Winetricks alone cannot run CODESYS\", {\n cause,\n });\n });\n const candidates = (process.env[\"PATH\"] ?? \"\").split(delimiter);\n const available = await Promise.all(\n candidates.map((path) =>\n access(resolve(path, \"script\"), constants.X_OK).then(\n () => true,\n () => false,\n ),\n ),\n );\n if (!available.some(Boolean)) {\n throw new Error(\n \"Headless Wine builds require the script utility (install util-linux on Linux)\",\n );\n }\n }\n await writeFile(resolve(directory, codesysCommandFilename), codesysCommand);\n const env = {\n ...hostEnv,\n CODESYS_BUILD_SCRIPT: await toWindowsPath(resolve(directory, \"worker.py\"), codesys.wine),\n CODESYS_BUILD_SESSION: await toWindowsPath(directory, codesys.wine),\n CODESYS_BUILD_EXE: await toWindowsPath(codesys.executable, codesys.wine),\n CODESYS_BUILD_PROFILE: codesys.profile,\n };\n const launcher = getHostCommand(codesys);\n const logPath = resolve(directory, \"codesys.log\");\n const exitPath = resolve(directory, \"launcher-exit.json\");\n await rm(exitPath, { force: true });\n const log = await open(logPath, \"w\");\n try {\n const child = spawn(launcher.executable, launcher.args, {\n cwd: directory,\n detached: true,\n windowsHide: true,\n env,\n stdio: [\"ignore\", log.fd, log.fd],\n });\n child.once(\"exit\", (code, signal) => {\n try {\n appendFileSync(logPath, `\\nCODESYS launcher exit status: ${signal ?? code}\\n`);\n } catch {\n // A failed diagnostic write must preserve the original process failure.\n }\n try {\n const temporary = `${exitPath}.${child.pid}.tmp`;\n writeFileSync(temporary, JSON.stringify({ pid: child.pid, code, signal }));\n renameSync(temporary, exitPath);\n } catch {\n // The log still records the exit if the optional status file cannot be published.\n }\n });\n await new Promise<void>((resolve, reject) => {\n child.once(\"error\", reject);\n child.once(\"spawn\", resolve);\n });\n if (!child.pid) {\n throw new Error(\"CODESYS launcher has no process ID\");\n }\n child.unref();\n return child.pid;\n } finally {\n await log.close();\n }\n };\n\n return {\n exitStatus: async (directory: string, pid: number) => {\n const path = resolve(directory, \"launcher-exit.json\");\n const value = await readFile(path, \"utf8\").catch((error: unknown) => {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return;\n throw error;\n });\n if (value === undefined) return;\n const status = exitSchema.parse(JSON.parse(value));\n if (status.pid !== pid) return;\n if (!native && status.code === 0 && status.signal === null) {\n const logPath = resolve(directory, \"codesys.log\");\n const log = (await readFile(logPath, \"utf8\"))\n // Terminal color escapes must not hide a native assertion signature.\n // eslint-disable-next-line no-control-regex\n .replace(/\\u001b\\[[0-?]*[ -/]*[@-~]/g, \"\")\n .replace(/\\r/g, \"\");\n // A Wine helper can abort under Rosetta while the main launcher returns 0.\n // That command still failed; publishing its artifacts would hide the fault.\n const assertion =\n /^assertion failed \\[[^\\n]+\\]:[^\\n]*\\n[ \\t]*\\(ThreadContext[^\\n]*\\)/m.exec(log);\n if (assertion) {\n throw new Error(\n `Wine translation aborted: ${assertion[0].replace(/\\s+/g, \" \")}. See ${logPath}`,\n );\n }\n }\n return status;\n },\n startWorker,\n terminate: async (pid: number) => {\n if (native) {\n await execute(\"taskkill.exe\", [\"/pid\", String(pid), \"/t\", \"/f\"], {\n env: hostEnv,\n timeout: timeouts.hostCommand,\n });\n return;\n }\n process.kill(-pid, \"SIGKILL\");\n },\n };\n};\n",
|
|
16
|
+
"import { execFile } from \"node:child_process\";\nimport { readdir, realpath } from \"node:fs/promises\";\nimport { relative, resolve, sep, win32 } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { ResolvedConfig } from \"../config\";\nimport { commandArgumentSchema } from \"./codesys-command\";\nimport { codesysTimeouts } from \"@tsplc/config/build\";\n\nconst execute = promisify(execFile);\n\nexport const toWindowsPath = async (\n path: string,\n wine: ResolvedConfig[\"codesys\"][\"wine\"],\n platform: NodeJS.Platform = process.platform,\n) => {\n if (platform === \"win32\") {\n return commandArgumentSchema.parse(win32.resolve(path));\n }\n if (!wine?.prefix) {\n throw new Error(\"Configure codesys.wine.prefix for CODESYS on macOS/Linux\");\n }\n\n // Resolve filesystem aliases (e.g. macOS /var -> /private/var) so the file\n // and drive roots are compared using the same paths. Fall back to the absolute\n // spelling when realpath cannot resolve the file, such as before it exists.\n const absolute = await realpath(resolve(path)).catch(() => resolve(path));\n // Wine stores drive mappings as symlinks, e.g. dosdevices/c: -> ../drive_c.\n // Reading these links avoids starting Wine just to convert a path.\n const devices = resolve(wine.prefix, \"dosdevices\");\n const drives = await readdir(devices).catch(() => []);\n const mappings = await Promise.all(\n drives\n .filter((drive) => /^[a-z]:$/i.test(drive))\n .map(async (drive) => {\n const root = await realpath(resolve(devices, drive)).catch(() => undefined);\n if (!root) {\n return;\n }\n\n const suffix = relative(root, absolute);\n // \"..\" or \"../...\" means the file is outside this drive's root.\n // Match a full segment so a name such as \"..notes\" remains valid.\n if (suffix === \"..\" || suffix.startsWith(`..${sep}`)) {\n return;\n }\n\n return {\n root,\n windows: win32.join(`${drive.toUpperCase()}\\\\`, ...suffix.split(sep)),\n };\n }),\n );\n // Mappings can overlap: C: -> /wine/drive_c and Z: -> / may both contain\n // the file. Prefer the longest matching root to use the most specific drive.\n const [mapping] = mappings\n .filter((value) => value !== undefined)\n .sort((a, b) => b.root.length - a.root.length);\n if (mapping) {\n return commandArgumentSchema.parse(mapping.windows);\n }\n\n // No readable drive mapping covers the path; ask Wine to convert it instead.\n const result = await execute(\n wine.pathBinary,\n [\"-w\", resolve(path)],\n // Wine inherits OS process settings.\n {\n env: { ...process.env, WINEPREFIX: wine.prefix, WINEDEBUG: wine.debug },\n timeout: codesysTimeouts.hostCommand,\n },\n );\n return commandArgumentSchema.parse(result.stdout.trim());\n};\n",
|
|
17
|
+
"import { basename } from \"node:path\";\nimport {\n declarationKeywords,\n globalSections,\n objectKinds,\n readDeclarationPragmas,\n readDeclarationSections,\n readDeclarationSemicolon,\n readIdentifier,\n readModifiers,\n readType,\n readVariableSection,\n variableSections,\n} from \"./declarations\";\nimport type { Token } from \"./lexer\";\nimport { createTokenReader, type TokenReader } from \"./reader\";\n\nexport type ObjectKind =\n (typeof objectKinds)[keyof typeof objectKinds] | \"dut\" | \"gvl\" | \"action\" | \"get\" | \"set\";\nexport type ParsedSource = {\n kind: ObjectKind;\n name: string;\n declaration: string;\n implementation?: string;\n returnType?: string;\n dutType?: \"structure\" | \"enumeration\" | \"union\" | \"alias\";\n persistent?: boolean;\n};\n\ntype ParseOptions = {\n filename?: string;\n declarationOnly?: boolean;\n name?: string;\n};\n\nconst dutTypes: Record<string, NonNullable<ParsedSource[\"dutType\"]>> = {\n STRUCT: \"structure\",\n UNION: \"union\",\n \"(\": \"enumeration\",\n};\n\nconst parseDut = (reader: TokenReader): ParsedSource => {\n reader.expect(\"TYPE\");\n readModifiers(reader);\n const name = readIdentifier(reader);\n if (reader.consume(\"EXTENDS\")) {\n readType(reader);\n }\n reader.expect(\":\");\n readDeclarationPragmas(reader);\n const dutType = dutTypes[reader.peek()?.value ?? \"\"] ?? \"alias\";\n while (reader.peek()?.value !== \"END_TYPE\") {\n if (reader.peek()?.value === \"TYPE\") {\n reader.fail(\"Only one TYPE declaration is allowed per file\");\n }\n reader.take();\n }\n reader.take();\n reader.consume(\";\");\n if (reader.peek()) {\n reader.fail(\"Unexpected content after END_TYPE\");\n }\n return { kind: \"dut\", name, declaration: reader.source, dutType };\n};\n\nconst parseGlobals = (reader: TokenReader, options: ParseOptions): ParsedSource => {\n const header = reader.peek();\n let persistent = false;\n while (reader.peek()) {\n readDeclarationPragmas(reader);\n if (!reader.peek()) {\n break;\n }\n if (!globalSections.has(reader.peek()?.value ?? \"\")) {\n reader.fail(\"Expected a global variable section\");\n }\n const start = reader.index;\n readVariableSection(reader);\n // Only the section modifiers select the CODESYS persistent-list object.\n // Comments, pragma strings, and variable names cannot select this role.\n for (const token of reader.tokens.slice(start + 1, reader.index)) {\n if (\n token.kind !== \"word\" ||\n ![\"CONSTANT\", \"RETAIN\", \"PERSISTENT\", \"NON_RETAIN\"].includes(token.value)\n ) {\n break;\n }\n persistent ||= token.value === \"PERSISTENT\";\n }\n }\n const name = options.name ?? basename(reader.filename, \".st\");\n if (!/^[A-Za-z_][A-Za-z_0-9]*$/.test(name)) {\n reader.fail(\"Global list requires an IEC filename or an explicit name\", header);\n }\n return {\n kind: \"gvl\",\n name,\n declaration: reader.source,\n ...(persistent && { persistent: true }),\n };\n};\n\nconst validateImplementation = (reader: TokenReader, tokens: Token[]) => {\n for (const token of tokens) {\n if (token.kind !== \"word\") {\n continue;\n }\n if (variableSections.has(token.value) || token.value === \"END_VAR\") {\n reader.fail(\n \"Variable declaration outside the declaration section; conditional declaration envelopes are not supported\",\n token,\n );\n }\n if (declarationKeywords.has(token.value)) {\n reader.fail(\n \"Nested objects must be separate child files, or the object terminator is mismatched\",\n token,\n );\n }\n }\n};\n\nconst splitObject = (\n reader: TokenReader,\n header: Token,\n kind: ObjectKind,\n options: ParseOptions,\n): Pick<ParsedSource, \"declaration\" | \"implementation\"> => {\n const terminator =\n header.value === \"FUNCTIONBLOCK\" ? \"END_FUNCTION_BLOCK\" : `END_${header.value}`;\n const remaining = reader.tokens.slice(reader.index);\n const terminatorIndex = remaining.findIndex(\n (token) => token.kind === \"word\" && token.value === terminator,\n );\n // Even interfaces and properties need END_* in combined files. Only an explicit\n // declaration-only input (e.g. a paired declaration.st) may omit it.\n if (terminatorIndex < 0 && !options.declarationOnly) {\n reader.fail(`Missing ${terminator}`);\n }\n const bodyTokens = terminatorIndex < 0 ? remaining : remaining.slice(0, terminatorIndex);\n const [endToken, next, afterSemicolon] =\n terminatorIndex < 0 ? [] : remaining.slice(terminatorIndex);\n const semicolon = next?.value === \";\" ? next : undefined;\n const unexpected = semicolon ? afterSemicolon : next;\n if (unexpected) {\n reader.fail(`Unexpected content after ${terminator}`, unexpected);\n }\n validateImplementation(reader, bodyTokens);\n\n const declarationOnly = options.declarationOnly || kind === \"interface\" || kind === \"property\";\n if (declarationOnly && bodyTokens.length) {\n reader.fail(\"Unexpected implementation in a declaration-only object\", bodyTokens[0]);\n }\n\n const declaration = reader.source.slice(0, reader.end);\n // Remove only END_* and its optional semicolon. Keep whitespace and trailing\n // comments in the body, or in the declaration for objects without a body.\n const body =\n reader.source.slice(reader.end, endToken?.start) +\n (endToken ? reader.source.slice((semicolon ?? endToken).end) : \"\");\n if (declarationOnly) {\n return { declaration: declaration + body };\n }\n return { declaration, implementation: body };\n};\n\nconst parsePou = (reader: TokenReader, options: ParseOptions): ParsedSource => {\n const header = reader.take();\n if (!(header.value in objectKinds)) {\n reader.fail(`Unsupported object header ${header.value}`, header);\n }\n const kind = objectKinds[header.value as keyof typeof objectKinds];\n readModifiers(reader);\n const name = readIdentifier(reader);\n const returnType = reader.consume(\":\") ? readType(reader) : undefined;\n if (returnType === undefined && kind === \"property\") {\n reader.fail(`${header.value} requires a return type`);\n }\n // Exported declarations may terminate the header itself with a semicolon.\n readDeclarationSemicolon(reader);\n readDeclarationSections(reader);\n return {\n kind,\n name,\n ...(returnType === undefined ? {} : { returnType }),\n ...splitObject(reader, header, kind, options),\n };\n};\n\n/** Parse only the object envelope and declarations. CODESYS validates executable ST. */\nexport const parseSource = (source: string, options: ParseOptions = {}): ParsedSource => {\n const reader = createTokenReader(source, options.filename ?? \"<source>\");\n readDeclarationPragmas(reader);\n const header = reader.peek();\n if (header?.value === \"TYPE\") {\n return parseDut(reader);\n }\n if (header && globalSections.has(header.value)) {\n return parseGlobals(reader, options);\n }\n return parsePou(reader, options);\n};\n",
|
|
18
|
+
"import type { Token } from \"./lexer\";\nimport type { TokenReader } from \"./reader\";\n\nexport const objectKinds = {\n PROGRAM: \"program\",\n FUNCTION_BLOCK: \"function_block\",\n FUNCTIONBLOCK: \"function_block\",\n FUNCTION: \"function\",\n METHOD: \"method\",\n INTERFACE: \"interface\",\n PROPERTY: \"property\",\n} as const;\n\nconst modifiers = new Set([\n \"PUBLIC\",\n \"PRIVATE\",\n \"PROTECTED\",\n \"INTERNAL\",\n \"FINAL\",\n \"ABSTRACT\",\n \"OVERRIDE\",\n]);\nexport const globalSections = new Set([\"VAR_GLOBAL\", \"VAR_CONFIG\"]);\nexport const variableSections = new Set([\n ...globalSections,\n \"VAR\",\n \"VAR_INPUT\",\n \"VAR_OUTPUT\",\n \"VAR_IN_OUT\",\n \"VAR_TEMP\",\n \"VAR_STAT\",\n \"VAR_INST\",\n \"VAR_EXTERNAL\",\n \"VAR_ACCESS\",\n \"VAR_GENERIC\",\n]);\nconst closingObjects = new Set(Object.keys(objectKinds).map((kind) => `END_${kind}`));\nexport const declarationKeywords = new Set([\n ...Object.keys(objectKinds),\n ...closingObjects,\n ...variableSections,\n \"END_VAR\",\n \"TYPE\",\n \"END_TYPE\",\n \"STRUCT\",\n \"END_STRUCT\",\n \"UNION\",\n \"END_UNION\",\n \"ACTION\",\n \"END_ACTION\",\n \"CONFIGURATION\",\n \"END_CONFIGURATION\",\n]);\n\nconst conditionalDirective = (token?: Token) => {\n if (token?.kind === \"pragma\") {\n return /^\\{\\s*(IF|ELSIF|ELSE|END_IF)\\b/i.exec(token.value)?.[1]?.toUpperCase();\n }\n};\nconst isDeclarationPragma = (token?: Token) =>\n token?.kind === \"pragma\" && !conditionalDirective(token);\n\nexport const readDeclarationPragmas = (reader: TokenReader) => {\n while (isDeclarationPragma(reader.peek())) {\n reader.take();\n }\n};\n\nexport const readDeclarationSemicolon = (reader: TokenReader) => {\n const token = reader.peek();\n // A semicolon on the next line may be the body's first empty statement.\n // Only attach it to a declaration when it terminates that same line.\n if (token?.value === \";\" && !/[\\r\\n]/.test(reader.source.slice(reader.end, token.start))) {\n reader.take();\n }\n};\n\nexport const readIdentifier = (reader: TokenReader) => {\n const token = reader.take();\n if (token.kind !== \"word\" || declarationKeywords.has(token.value)) {\n reader.fail(\"Expected an IEC identifier\", token);\n }\n return reader.source.slice(token.start, token.end);\n};\n\nconst isOverrideModifier = (reader: TokenReader) => {\n // OVERRIDE is also an established IEC name (e.g. OSCAT's function).\n // A modifier needs a following name on the same line, not a body statement.\n const name = reader.peek(1);\n return (\n name?.kind === \"word\" &&\n !declarationKeywords.has(name.value) &&\n ![\"(\", \"[\", \":=\", \".\", \"^\"].includes(reader.peek(2)?.value ?? \"\") &&\n !/[\\r\\n]/.test(reader.source.slice(reader.peek()?.end, name.start))\n );\n};\n\nexport const readModifiers = (reader: TokenReader) => {\n while (modifiers.has(reader.peek()?.value ?? \"\")) {\n if (reader.peek()?.value === \"OVERRIDE\" && !isOverrideModifier(reader)) {\n return;\n }\n reader.take();\n }\n};\n\nconst typeDelimiters = { \"(\": \")\", \"[\": \"]\", \"<\": \">\" } as const;\n\nconst readDelimitedType = (reader: TokenReader, open: keyof typeof typeDelimiters) => {\n reader.expect(open);\n const closings = [typeDelimiters[open]];\n while (closings.length) {\n const token = reader.take();\n if (token.kind === \"string\" || token.kind === \"pragma\") {\n continue;\n }\n if (token.value === \"(\" || token.value === \"[\") {\n closings.push(typeDelimiters[token.value]);\n } else if (token.value === \")\" || token.value === \"]\") {\n if (closings.pop() !== token.value) {\n reader.fail(`Mismatched delimiter ${token.value}`, token);\n }\n } else if (open === \"<\" && closings.at(-1) === \">\") {\n // Inside parentheses, < and > are comparisons, not generic delimiters:\n // FB_Base<(Size := BOOL_TO_INT(1 < 2))>.\n if (token.value === \"<\") {\n closings.push(\">\");\n }\n if (token.value === \">\") {\n closings.pop();\n }\n }\n if (declarationKeywords.has(token.value) || token.value === \";\") {\n reader.fail(`Unclosed ${open}`, token);\n }\n }\n};\n\nexport const readType = (reader: TokenReader): string => {\n const start = reader.peek()?.start ?? reader.source.length;\n // Prefix types can nest arbitrarily; iteration avoids a JavaScript stack limit.\n while (true) {\n if ([\"POINTER\", \"REFERENCE\", \"REF_TO\"].includes(reader.peek()?.value ?? \"\")) {\n if (reader.take().value !== \"REF_TO\") {\n reader.expect(\"TO\");\n }\n continue;\n }\n if (reader.consume(\"ARRAY\")) {\n readDelimitedType(reader, \"[\");\n reader.expect(\"OF\");\n continue;\n }\n break;\n }\n readIdentifier(reader);\n while (reader.consume(\".\")) {\n readIdentifier(reader);\n }\n for (const open of [\"(\", \"[\", \"<\"] as const) {\n if (reader.peek()?.value === open) {\n readDelimitedType(reader, open);\n }\n }\n return reader.source.slice(start, reader.end);\n};\n\nexport const readVariableSection = (reader: TokenReader) => {\n reader.take();\n const conditionals: { hasElse: boolean }[] = [];\n while (reader.peek()?.value !== \"END_VAR\") {\n const token = reader.take();\n if (variableSections.has(token.value) || closingObjects.has(token.value)) {\n reader.fail(\"Missing END_VAR\", token);\n }\n const directive = conditionalDirective(token);\n if (!directive) {\n continue;\n }\n if (directive === \"IF\") {\n conditionals.push({ hasElse: false });\n continue;\n }\n const current = conditionals.at(-1);\n if (!current) {\n return reader.fail(\"Unmatched conditional pragma\", token);\n }\n if (directive === \"END_IF\") {\n conditionals.pop();\n continue;\n }\n if (current.hasElse) {\n reader.fail(\"Conditional branch after ELSE\", token);\n }\n current.hasElse = directive === \"ELSE\";\n }\n if (conditionals.length) {\n reader.fail(\"Conditional pragmas must remain inside one variable section\");\n }\n reader.take();\n readDeclarationSemicolon(reader);\n};\n\nexport const readDeclarationSections = (reader: TokenReader) => {\n while (reader.peek()) {\n // Pragmas belong to the declaration only when another declaration follows.\n // Look ahead without consuming them so a pragma-only body stays intact.\n let ahead = 0;\n while (isDeclarationPragma(reader.peek(ahead))) {\n ahead++;\n }\n const next = reader.peek(ahead)?.value ?? \"\";\n if (variableSections.has(next)) {\n readDeclarationPragmas(reader);\n readVariableSection(reader);\n continue;\n }\n if (next !== \"EXTENDS\" && next !== \"IMPLEMENTS\") {\n return;\n }\n // CODESYS generic FBs can place these clauses after VAR_GENERIC.\n readDeclarationPragmas(reader);\n reader.take();\n readType(reader);\n while (reader.consume(\",\")) {\n readType(reader);\n }\n }\n};\n",
|
|
19
|
+
"export type Token = {\n kind: \"word\" | \"string\" | \"pragma\" | \"symbol\";\n value: string;\n start: number;\n end: number;\n};\n\nexport class StSyntaxError extends Error {\n constructor(source: string, offset: number, filename: string, message: string) {\n const lines = source.slice(0, offset).split(/\\r\\n|\\r|\\n/);\n super(`${filename}:${lines.length}:${(lines.at(-1)?.length ?? 0) + 1}: ${message}`);\n this.name = \"StSyntaxError\";\n }\n}\n\n/** Keep original offsets: splitting must preserve comments, pragmas and source spelling. */\nexport const tokenize = (source: string, filename = \"<source>\"): Token[] => {\n const tokens: Token[] = [];\n let offset = 0;\n const fail = (start: number, message: string): never => {\n throw new StSyntaxError(source, start, filename, message);\n };\n const quoted = () => {\n const start = offset;\n const quote = source[offset++];\n while (offset < source.length) {\n // IEC strings escape characters (including quotes and $ itself) with $.\n if (source[offset] === \"$\") {\n offset += 2;\n } else if (source[offset++] === quote) {\n return;\n }\n }\n fail(start, \"Unterminated string\");\n };\n while (offset < source.length) {\n const start = offset;\n const character = source[offset] ?? \"\";\n if (/\\s|\\uFEFF/.test(character)) {\n offset++;\n continue;\n }\n if (source.startsWith(\"//\", offset)) {\n while (offset < source.length && !/[\\r\\n]/.test(source[offset] ?? \"\")) {\n offset++;\n }\n continue;\n }\n if (source.startsWith(\"(*\", offset)) {\n offset += 2;\n let depth = 1;\n while (offset < source.length && depth > 0) {\n if (source.startsWith(\"(*\", offset)) {\n depth++;\n offset += 2;\n } else if (source.startsWith(\"*)\", offset)) {\n depth--;\n offset += 2;\n } else {\n offset++;\n }\n }\n if (depth) {\n fail(start, \"Unterminated block comment\");\n }\n continue;\n }\n if (character === \"'\" || character === '\"') {\n quoted();\n tokens.push({\n kind: \"string\",\n value: source.slice(start, offset),\n start,\n end: offset,\n });\n continue;\n }\n if (character === \"{\") {\n offset++;\n while (offset < source.length && source[offset] !== \"}\") {\n if (source[offset] === \"'\" || source[offset] === '\"') {\n quoted();\n } else {\n offset++;\n }\n }\n if (offset === source.length) {\n fail(start, \"Unterminated pragma\");\n }\n offset++;\n tokens.push({\n kind: \"pragma\",\n value: source.slice(start, offset),\n start,\n end: offset,\n });\n continue;\n }\n if (/[A-Za-z_]/.test(character)) {\n offset++;\n while (/[A-Za-z_0-9]/.test(source[offset] ?? \"\")) {\n offset++;\n }\n tokens.push({\n kind: \"word\",\n value: source.slice(start, offset).toUpperCase(),\n start,\n end: offset,\n });\n continue;\n }\n offset++;\n const pair = source.slice(start, offset + 1);\n if ([\":=\", \"=>\", \"..\", \"<=\", \">=\", \"<>\", \"**\"].includes(pair)) {\n offset++;\n }\n tokens.push({\n kind: \"symbol\",\n value: source.slice(start, offset),\n start,\n end: offset,\n });\n }\n return tokens;\n};\n",
|
|
20
|
+
"import { StSyntaxError, type Token, tokenize } from \"./lexer\";\n\n/** Traverse tokens without losing the source offsets needed for an exact split. */\nexport const createTokenReader = (source: string, filename: string) => {\n const tokens = tokenize(source, filename);\n let index = 0;\n const peek = (ahead = 0) => tokens[index + ahead];\n const fail = (message: string, token = peek()): never => {\n throw new StSyntaxError(source, token?.start ?? source.length, filename, message);\n };\n const take = (): Token => {\n const token = peek();\n if (!token) {\n return fail(\"Unexpected end of declaration\");\n }\n index++;\n return token;\n };\n const expect = (value: string) => {\n if (peek()?.value !== value) {\n fail(`Expected ${value}`);\n }\n return take();\n };\n const consume = (value: string) => {\n if (peek()?.value === value) {\n return take();\n }\n };\n\n return {\n source,\n filename,\n tokens,\n peek,\n take,\n expect,\n consume,\n fail,\n get index() {\n return index;\n },\n // The declaration ends at the last consumed token, before any body whitespace.\n get end() {\n return tokens[index - 1]?.end ?? 0;\n },\n };\n};\n\nexport type TokenReader = ReturnType<typeof createTokenReader>;\n",
|
|
21
|
+
"import type { SourceObject } from \"./sources.ts\";\nimport { tokenize, type Token } from \"./st/lexer.ts\";\nimport { variableSections } from \"./st/declarations.ts\";\n\nexport interface DirectIoBinding {\n address: string;\n type?: string;\n}\n// A span binds at its first element: ARRAY[l..u] OF <element> with consecutive addresses.\nconst arrayType = /^ARRAY\\s*\\[\\s*(-?\\d+)\\s*\\.\\.\\s*(-?\\d+)\\s*\\]\\s*OF\\s+(\\w+)$/;\nconst layout = (type: string) => {\n const array = arrayType.exec(type);\n return array\n ? { element: array[3]!, length: Number(array[2]) - Number(array[1]) + 1 }\n : { element: type, length: 1 };\n};\nconst widths: Record<string, string> = {\n BOOL: \"X\",\n BYTE: \"B\",\n SINT: \"B\",\n USINT: \"B\",\n WORD: \"W\",\n INT: \"W\",\n UINT: \"W\",\n DWORD: \"D\",\n DINT: \"D\",\n UDINT: \"D\",\n REAL: \"D\",\n};\n\n/** Apply the shared mapping to declarations in memory; authored ST stays untouched. */\nexport function bindStructuredTextIo(\n objects: SourceObject[],\n bindings: Record<string, DirectIoBinding>,\n) {\n const declarations: {\n object: SourceObject;\n name: string;\n names: Token[];\n colon: Token;\n type: string;\n }[] = [];\n const visit = (object: SourceObject) => {\n const tokens = tokenize(object.declaration, object.source);\n let section = false,\n start = 0;\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]!;\n if (variableSections.has(token.value)) {\n section = true;\n start = i + 1;\n continue;\n }\n if (token.value === \"END_VAR\") {\n section = false;\n continue;\n }\n if (!section || token.value !== \";\") continue;\n const part = tokens.slice(start, i).filter((t) => t.kind !== \"pragma\");\n start = i + 1;\n const colonIndex = part.findIndex((t) => t.value === \":\");\n if (colonIndex < 1) continue;\n const names = part\n .slice(0, colonIndex)\n .filter(\n (t) => t.kind === \"word\" && ![\"CONSTANT\", \"RETAIN\", \"PERSISTENT\", \"AT\"].includes(t.value),\n );\n const at = part.findIndex((t) => t.value === \"AT\");\n const variables = at < 0 ? names : names.filter((t) => t.start < part[at]!.start);\n const initializer = part.findIndex((t, index) => index > colonIndex && t.value === \":=\");\n const typeTokens = part.slice(colonIndex + 1, initializer < 0 ? undefined : initializer);\n const type = typeTokens.length\n ? object.declaration\n .slice(typeTokens[0]!.start, typeTokens.at(-1)!.end)\n .replace(/\\s+/g, \" \")\n .toUpperCase()\n : \"\";\n for (const name of variables)\n declarations.push({\n object,\n name: name.value,\n names: variables,\n colon: part[colonIndex]!,\n type,\n });\n }\n object.children.forEach(visit);\n };\n objects.forEach(visit);\n const edits = new Map<SourceObject, { start: number; end: number; text: string }[]>();\n for (const [symbol, binding] of Object.entries(bindings)) {\n const parts = symbol.toUpperCase().split(\".\");\n if (parts.length > 2)\n throw new Error(`${symbol}: direct IO maps a scalar declaration, not a nested field.`);\n const matches = declarations.filter(\n (d) =>\n d.name === parts.at(-1) && (parts.length === 1 || d.object.name.toUpperCase() === parts[0]),\n );\n if (matches.length !== 1)\n throw new Error(\n `${symbol}: expected one ST variable declaration, found ${matches.length}. Use Object.Variable to disambiguate.`,\n );\n const declaration = matches[0]!;\n if (declaration.names.length !== 1)\n throw new Error(`${symbol}: declare mapped IO variables separately.`);\n const declared = layout(declaration.type);\n if (\n !widths[declared.element] ||\n (declared.length > 1 && declared.element === \"BOOL\") ||\n binding.address[2] !== widths[declared.element]\n )\n throw new Error(`${symbol}: ${declaration.type} is incompatible with ${binding.address}.`);\n const expected = binding.type && layout(binding.type.replace(/\\s+/g, \" \").toUpperCase());\n if (expected && (expected.element !== declared.element || expected.length !== declared.length))\n throw new Error(`${symbol}: expected ${binding.type}, found ${declaration.type}.`);\n const list = edits.get(declaration.object) ?? [];\n const start = declaration.names[0]!.end;\n if (list.some((e) => e.start === start))\n throw new Error(`${symbol}: the variable has more than one IO binding.`);\n list.push({ start, end: declaration.colon.start, text: ` AT ${binding.address} ` });\n edits.set(declaration.object, list);\n }\n for (const [object, list] of edits)\n for (const edit of list.sort((a, b) => b.start - a.start))\n object.declaration =\n object.declaration.slice(0, edit.start) + edit.text + object.declaration.slice(edit.end);\n}\n",
|
|
22
|
+
"import { createHash } from \"node:crypto\";\nimport { access, copyFile, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { buildFiles, publishBuild, readBuild } from \"./artifacts\";\nimport { dockerImage, type ResolvedConfig } from \"./config\";\nimport { buildInDocker } from \"./docker-build\";\nimport { createCodesysWorker, withWorkerLock } from \"./host/codesys-worker\";\nimport { loadSources } from \"./sources\";\nimport { toWindowsPath } from \"./host/windows-path.ts\";\n\nexport const buildProject = async (config: ResolvedConfig) => {\n if (!config.docker) throw new Error(\"Builds require a Docker builder image.\");\n return buildInDocker(config, dockerImage);\n};\n\n/** The container runner owns Wine; this operation is not a public host build. */\nexport const buildInContainer = async (config: ResolvedConfig) => {\n return withWorkerLock(config, async () => {\n // Invalidate the previous build before validation, so run cannot deploy stale\n // output after a failed rebuild. Keep the last project available for inspection.\n await rm(resolve(config.outDir, buildFiles.receipt), { force: true });\n const sources = await loadSources(config);\n await access(config.template);\n const worker = createCodesysWorker(config);\n const session = await worker.launch();\n const directory = resolve(config.outDir, \".codesys/build\");\n await rm(directory, { recursive: true, force: true });\n await mkdir(resolve(directory, \"runtime\"), { recursive: true });\n const template = resolve(directory, \"Template.project\");\n await copyFile(config.template, template);\n // CODESYS imports each adapter's EDS from the build directory.\n const deviceTree = config.deviceTree && {\n ...config.deviceTree,\n devices: await Promise.all(\n config.deviceTree.devices.map(async (device) => {\n const eds = `${buildFiles.devices}/${device.name}.eds`;\n await mkdir(resolve(directory, buildFiles.devices), { recursive: true });\n await writeFile(resolve(directory, eds), device.eds);\n // The digest keys project reuse on the description's content.\n return { ...device, eds, sha256: createHash(\"sha256\").update(device.eds).digest(\"hex\") };\n }),\n ),\n };\n const request = {\n libraryReferences: config.libraryReferences,\n libraries: await Promise.all(\n (config.libraries ?? []).map(async (library) => ({\n ...library,\n path: await toWindowsPath(library.path, config.codesys.wine),\n })),\n ),\n ...sources,\n task: config.task,\n ...(config.tasks && { tasks: config.tasks }),\n removeObjects: config.removeObjects,\n symbols: config.symbols,\n ...(deviceTree && { deviceTree }),\n ...(config.controller && { controller: config.controller }),\n mode: \"build\",\n output: buildFiles.output,\n project: buildFiles.project,\n archive: buildFiles.archive,\n receipt: buildFiles.receipt,\n template: \"Template.project\",\n templateHash: createHash(\"sha256\")\n .update(await readFile(template))\n .digest(\"hex\"),\n };\n await writeFile(resolve(directory, \"request.json\"), JSON.stringify(request, null, 2));\n console.log(`CODESYS build: ${config.outDir}`);\n try {\n await worker.request(session, { action: \"build\" }, config.timeouts.build);\n const compiled = await readBuild(directory);\n if (config.tasks && JSON.stringify(compiled.tasks) !== JSON.stringify(config.tasks)) {\n throw new Error(\"CODESYS build receipt does not match the requested task plan\");\n }\n // Builds and runs share the lock. Removing the receipt above keeps a failed\n // publication from looking complete even if only some files were replaced.\n return await publishBuild(compiled, config.outDir);\n } catch (cause) {\n throw new Error(\n `CODESYS build failed. Inspect ${directory}/progress.log, error.txt and ${session.directory}/codesys.log`,\n { cause },\n );\n }\n });\n};\n",
|
|
23
|
+
"export {\n configSchema,\n controllerSchema,\n cyclicTasksSchema,\n dockerImage,\n defineBuildConfig as defineConfig,\n resolveConfig,\n loadConfig,\n type CodesysBuildConfig,\n type ResolvedConfig,\n type CyclicTask,\n} from \"@tsplc/config/build\";\n",
|
|
24
|
+
"import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, mkdtemp, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { promisify } from \"node:util\";\nimport { z } from \"zod\";\nimport { controllerSchema, dockerImage, type ResolvedConfig } from \"./config\";\nimport { controllerFailureFile } from \"./diagnostics.ts\";\nimport { prepareContainerRun, runDocker } from \"./docker-run.ts\";\n\nconst execute = promisify(execFile);\nconst imageIdSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/);\nconst endpointSchema = z.strictObject({\n host: z.string().nonempty(),\n port: z.number().int().min(1).max(65535),\n});\nexport const controllerResultSchema = z.strictObject({\n schemaVersion: z.literal(1),\n operationId: z.uuid(),\n operation: z.enum([\"download\", \"online-change\", \"inspect\"]),\n imageId: imageIdSchema,\n templateHash: z.string().regex(/^[a-f0-9]{64}$/),\n target: z.strictObject({\n network: z.string().nonempty(),\n gateway: endpointSchema,\n device: endpointSchema,\n controller: controllerSchema.optional(),\n }),\n generation: z.string().nonempty(),\n application: z.string().nonempty(),\n applicationGuid: z.string().nonempty(),\n controllerIds: z.strictObject({\n codeId: z.string().nonempty(),\n dataId: z.string().nonempty(),\n }),\n state: z.string().nonempty(),\n values: z.record(z.string(), z.string()),\n});\nexport type ControllerResult = z.infer<typeof controllerResultSchema>;\nexport type ControllerUpdateOptions = {\n initializeUser?: boolean;\n read?: string[];\n};\n\n/** Checks the settings every engineering connection needs and names its builder image and target. */\nconst controllerConnection = async (config: ResolvedConfig) => {\n if (!config.docker || !config.online) {\n throw new Error(\n \"Docker image and online gateway/device configuration are required for controller operations\",\n );\n }\n const environmentNames = config.online.credentials\n ? [config.online.credentials.usernameEnv, config.online.credentials.passwordEnv]\n : [];\n for (const name of environmentNames) {\n if (process.env[name] === undefined) {\n throw new Error(`Controller credential environment variable ${name} is not set`);\n }\n }\n const { stdout } = await execute(\n \"docker\",\n [\"image\", \"inspect\", \"--format\", \"{{.Id}}\", dockerImage],\n { timeout: config.timeouts.hostCommand },\n ).catch((cause: unknown) => {\n throw new Error(\n `Cannot inspect Docker builder image ${dockerImage}. Install and start Docker, then run tsplc-build configure if the image is missing`,\n { cause },\n );\n });\n return {\n environmentNames,\n imageId: imageIdSchema.parse(stdout.trim()),\n templateHash: createHash(\"sha256\")\n .update(await readFile(config.template))\n .digest(\"hex\"),\n target: {\n network: config.online.network,\n gateway: config.online.gateway,\n device: config.online.device,\n controller: config.controller,\n },\n };\n};\n\nconst controllerOperation = async (\n config: ResolvedConfig,\n operation: ControllerResult[\"operation\"],\n options: ControllerUpdateOptions,\n): Promise<ControllerResult> => {\n const { environmentNames, imageId, templateHash, target } = await controllerConnection(config);\n const operationId = randomUUID();\n const requestDirectory = await mkdtemp(resolve(tmpdir(), \"codesys-controller-\"));\n const diagnostics = resolve(config.outDir, \".codesys/controller\");\n const failure = resolve(config.outDir, controllerFailureFile);\n try {\n await mkdir(config.outDir, { recursive: true });\n await rm(failure, { force: true });\n await runDocker(\n [\n \"run\",\n \"--rm\",\n ...(await prepareContainerRun(config, requestDirectory, {\n network: target.network,\n environment: environmentNames,\n sources: operation !== \"inspect\",\n })),\n imageId,\n operation,\n \"--request\",\n \"/input/config.json\",\n \"--operation-id\",\n operationId,\n \"--image-id\",\n imageId,\n ...(options.initializeUser ? [\"--initialize-user\"] : []),\n ...(options.read ? [\"--read\", JSON.stringify(options.read)] : []),\n ],\n (status) =>\n `Docker controller operation failed (${status}). Inspect ${diagnostics} for diagnostics`,\n ).catch(async (cause: unknown) => {\n if (!existsSync(failure)) throw cause;\n // A CODESYS failure arrives as a Python traceback, whose last line names it.\n const reason = (await readFile(failure, \"utf8\")).trim().split(\"\\n\").at(-1);\n throw new Error(`${reason}. Inspect ${diagnostics} for diagnostics`, { cause });\n });\n const result = await readFile(resolve(diagnostics, \"result.json\"), \"utf8\")\n .then((content) => controllerResultSchema.parse(JSON.parse(content)))\n .catch((cause: unknown) => {\n throw new Error(\n `Docker did not produce a valid controller receipt. Inspect ${diagnostics} for diagnostics`,\n { cause },\n );\n });\n if (\n result.operationId !== operationId ||\n result.operation !== operation ||\n result.imageId !== imageId ||\n result.templateHash !== templateHash ||\n JSON.stringify(result.target) !== JSON.stringify(target)\n ) {\n throw new Error(\n `Controller receipt does not match this operation's image, template or target. Inspect ${diagnostics} for diagnostics`,\n );\n }\n return result;\n } finally {\n await rm(requestDirectory, { recursive: true, force: true });\n }\n};\n\n/** Download or apply an online change using the original CODESYS Docker compiler. */\nexport const updateController = (\n config: ResolvedConfig,\n operation: \"download\" | \"online-change\",\n options: ControllerUpdateOptions = {},\n) => controllerOperation(config, operation, options);\n\n/** Read the controller using the runner's saved compilation baseline. */\nexport const inspectController = (config: ResolvedConfig, read?: string[]) =>\n controllerOperation(config, \"inspect\", { read });\n\n/**\n * Ends every refusal that only a full download resolves, so callers can offer one. The Python\n * online operations end theirs with the same words.\n */\nexport const explicitDownload = \"use an explicit download\";\n\nexport const loginCommandSchema = z.discriminatedUnion(\"command\", [\n z.strictObject({ command: z.literal(\"state\") }),\n z.strictObject({\n command: z.literal(\"read\"),\n expressions: z.array(z.string().nonempty()).nonempty(),\n }),\n z.strictObject({\n command: z.enum([\"write\", \"force\"]),\n values: z.record(z.string().nonempty(), z.string().nonempty()),\n }),\n // No expressions unforces everything; `restore` puts back the value from before forcing.\n z.strictObject({\n command: z.literal(\"unforce\"),\n expressions: z.array(z.string().nonempty()),\n restore: z.boolean(),\n }),\n z.strictObject({ command: z.enum([\"start\", \"stop\"]) }),\n z.strictObject({ command: z.literal(\"reset\"), kind: z.enum([\"Warm\", \"Cold\"]) }),\n]);\nexport type LoginCommand = z.infer<typeof loginCommandSchema>;\nexport const loginResultSchema = z.union([\n z.strictObject({ values: z.record(z.string(), z.string()) }),\n z.strictObject({ state: z.string(), forced: z.array(z.string()) }),\n]);\nexport type LoginResult = z.infer<typeof loginResultSchema>;\nconst loginReplySchema = z.discriminatedUnion(\"ok\", [\n z.strictObject({ ok: z.literal(true), result: z.unknown() }),\n z.strictObject({ ok: z.literal(false), error: z.string() }),\n]);\n\n/** The port a login container serves its commands on, published to the host's loopback only. */\nconst loginPort = 4851;\n\nconst docker = (args: string[], timeout: number) =>\n execute(\"docker\", args, { timeout }).then(({ stdout }) => stdout.trim());\n\nconst isRunning = async (name: string, timeout: number) =>\n (await docker([\"container\", \"ls\", \"--quiet\", \"--filter\", `name=^${name}$`], timeout)) !== \"\";\n\n/** A login held open in builder container `name`; it ends with `close` or when the container stops. */\nconst attachLogin = async (name: string, timeout: number) => {\n const published = await docker([\"port\", name, String(loginPort)], timeout);\n const url = `http://${published.split(\"\\n\")[0]}`;\n const call = async (init: RequestInit) => {\n const reply = loginReplySchema.parse(await (await fetch(url, init)).json());\n if (!reply.ok) throw new Error(reply.error);\n return reply.result;\n };\n return {\n name,\n /** The relay answers only once CODESYS has logged in. */\n ready: () =>\n fetch(url)\n .then((response) => response.ok)\n .catch(() => false),\n send: async (command: LoginCommand) =>\n loginResultSchema.parse(\n await call({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(command),\n }),\n ),\n /** Logs out and waits for the container to stop. */\n close: async () => {\n await call({ method: \"DELETE\" });\n await docker([\"wait\", name], timeout);\n await docker([\"rm\", name], timeout);\n },\n };\n};\nexport type ControllerLogin = Awaited<ReturnType<typeof attachLogin>>;\n\n/** The login in container `name`, if one is running; it outlives the process that opened it. */\nexport const findControllerLogin = async (name: string) =>\n (await isRunning(name, 15_000)) ? attachLogin(name, 15_000) : undefined;\n\n/**\n * Logs in to the running application from the saved download baseline, in a detached builder\n * container named `name`. Commands then take seconds instead of a CODESYS start each.\n */\nexport const openControllerLogin = async (config: ResolvedConfig, name: string) => {\n const { environmentNames, imageId, target } = await controllerConnection(config);\n const timeout = config.timeouts.hostCommand;\n // A login that failed to open leaves its stopped container for diagnostics until the next one.\n await docker([\"rm\", \"--force\", name], timeout);\n // The request is overwritten in place: a bind mount of a recreated directory can still show\n // Docker Desktop's cached, empty view of the deleted one.\n const requestDirectory = resolve(config.outDir, \".codesys/login-request\");\n await mkdir(requestDirectory, { recursive: true });\n await docker(\n [\n \"run\",\n \"--detach\",\n \"--name\",\n name,\n \"--publish\",\n `127.0.0.1::${loginPort}`,\n ...(await prepareContainerRun(config, requestDirectory, {\n network: target.network,\n environment: environmentNames,\n sources: false,\n })),\n imageId,\n \"login\",\n \"--request\",\n \"/input/config.json\",\n \"--image-id\",\n imageId,\n \"--port\",\n String(loginPort),\n ],\n timeout,\n );\n const deadline = Date.now() + config.timeouts.startup + config.timeouts.build;\n while (Date.now() < deadline) {\n if (!(await isRunning(name, timeout))) {\n const logs = await execute(\"docker\", [\"logs\", \"--tail\", \"40\", name], { timeout });\n throw new Error(`The controller login failed:\\n${logs.stdout}${logs.stderr}`);\n }\n const login = await attachLogin(name, timeout);\n if (await login.ready()) return login;\n await delay(2000);\n }\n await docker([\"rm\", \"--force\", name], timeout);\n throw new Error(\"The controller login did not open in time\");\n};\n",
|
|
25
|
+
"import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { cp, mkdir, mkdtemp, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { readBuild } from \"./artifacts\";\nimport { dockerImage, type ResolvedConfig } from \"./config\";\nimport { prepareDockerContext } from \"./docker-context.ts\";\nimport { buildFailureFile, buildFailureSchema, CodesysCompilerError } from \"./diagnostics.ts\";\nimport { prepareContainerRun, runDocker } from \"./docker-run.ts\";\nimport { packageDirectory } from \"./package-path.ts\";\n\nconst execute = promisify(execFile);\n\n/** Install the IDE and its prerequisites in the Docker builder image. */\nexport const configureDocker = async () => {\n const image = dockerImage;\n const { stdout } = await execute(\n \"docker\",\n [\"info\", \"--format\", \"{{.OSType}}/{{.Architecture}}\"],\n { timeout: 30_000 },\n ).catch((cause: unknown) => {\n throw new Error(\"Cannot connect to Docker. Install and start Docker Desktop or Docker Engine\", {\n cause,\n });\n });\n const architecture = stdout.trim();\n const arm = architecture === \"linux/aarch64\" || architecture === \"linux/arm64\";\n if (!arm && architecture !== \"linux/x86_64\" && architecture !== \"linux/amd64\") {\n throw new Error(\"The builder requires a Linux Docker server on ARM64 or AMD64\");\n }\n const context = await mkdtemp(resolve(tmpdir(), \"codesys-installer-\"));\n let buildContext: string | undefined;\n try {\n buildContext = await prepareDockerContext();\n const cache = resolve(context, \"winetricks\");\n await mkdir(cache);\n if (process.env[\"CODESYS_WINETRICKS_CACHE\"]) {\n await cp(process.env[\"CODESYS_WINETRICKS_CACHE\"], cache, {\n recursive: true,\n });\n }\n console.log(\n `Preparing Docker builder (${image}). Downloading and installing CODESYS 3.5.22.30 and prerequisites.`,\n );\n await runDocker(\n [\n \"build\",\n \"--platform\",\n \"linux/amd64\",\n \"--build-arg\",\n `SETUP_BASE=${arm ? \"arm-setup\" : \"base\"}`,\n \"--build-arg\",\n `SETUP_PLATFORM=${arm ? \"linux/arm64\" : \"linux/amd64\"}`,\n \"--build-arg\",\n \"INSTALLER_SOURCE=installer-download\",\n \"--progress\",\n \"plain\",\n \"--build-context\",\n `installer=${context}`,\n \"-f\",\n resolve(buildContext, \"docker/Dockerfile\"),\n \"-t\",\n image,\n buildContext,\n ],\n (status) =>\n `Docker configuration failed (${status}). Review the image-build output and run tsplc configure again`,\n );\n return image;\n } finally {\n await Promise.all([\n rm(context, { recursive: true, force: true }),\n ...(buildContext ? [rm(buildContext, { recursive: true, force: true })] : []),\n ]);\n }\n};\n\nexport const runtimeImage = \"tsplc-control-linux-sl:4.22.0.0\";\n\n/** Build the local CODESYS Control for Linux SL runtime, the same device as a production build. */\nexport const configureRuntime = async () => {\n const context = resolve(packageDirectory, \"docker/control-linux-sl\");\n console.log(`Preparing the local PLC runtime (${runtimeImage}).`);\n await runDocker(\n [\"build\", \"--platform\", \"linux/amd64\", \"--progress\", \"plain\", \"-t\", runtimeImage, context],\n (status) => `Runtime image build failed (${status}). Review the image-build output`,\n );\n return runtimeImage;\n};\n\nexport const gatewayImage = \"tsplc-edge-gateway:4.22.0.0\";\n\n/** Build the CODESYS Edge Gateway that builder containers reach a plant controller through. */\nexport const configureGateway = async () => {\n const context = resolve(packageDirectory, \"docker/edge-gateway\");\n console.log(`Preparing the CODESYS gateway (${gatewayImage}).`);\n await runDocker(\n [\"build\", \"--platform\", \"linux/amd64\", \"--progress\", \"plain\", \"-t\", gatewayImage, context],\n (status) => `Gateway image build failed (${status}). Review the image-build output`,\n );\n return gatewayImage;\n};\n\nexport const buildInDocker = async (config: ResolvedConfig, image: string) => {\n const requestDirectory = await mkdtemp(resolve(tmpdir(), \"codesys-docker-\"));\n try {\n const operationId = randomUUID();\n await mkdir(config.outDir, { recursive: true });\n const failurePath = resolve(config.outDir, buildFailureFile);\n await rm(failurePath, { force: true });\n const args = [\n \"run\",\n \"--rm\",\n ...(await prepareContainerRun(config, requestDirectory, { network: \"none\", sources: true })),\n image,\n \"--request\",\n \"/input/config.json\",\n \"--operation-id\",\n operationId,\n ];\n console.log(`Building with Docker (${image})`);\n try {\n await runDocker(\n args,\n (status) =>\n `Docker build failed (${status}). Run tsplc configure if the image is missing; inspect ${config.outDir}/.codesys/docker for compiler logs`,\n );\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n const failure = await readFile(failurePath, \"utf8\")\n .then((text) => buildFailureSchema.parse(JSON.parse(text)))\n .catch((error: unknown) => {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return;\n throw new AggregateError(\n [cause, error],\n `${message}. Invalid CODESYS failure metadata (${failurePath})`,\n { cause: error },\n );\n });\n if (!failure) throw cause;\n if (failure.operationId !== operationId)\n throw new Error(\n `${message}. CODESYS failure metadata belongs to a different Docker build`,\n {\n cause,\n },\n );\n if (cause instanceof Error) {\n // The mapper keeps ordinary error messages as notes, while vendor\n // diagnostics supply their own text. Preserve shutdown context there.\n cause.message = `${message}\\n${failure.message}`;\n if (failure.diagnostics.length)\n cause.cause = new CodesysCompilerError(failure.message, failure.diagnostics);\n }\n throw cause;\n }\n return await readBuild(config.outDir);\n } finally {\n await rm(requestDirectory, { recursive: true, force: true });\n }\n};\n",
|
|
26
|
+
"import { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { basename, relative, resolve } from \"node:path\";\nimport type { LibraryDependency } from \"@tsplc/config\";\n\nexport const libraryRegistry = \"https://store-archive.codesys.com/CODESYSLibs\";\nconst libraryFile = /\\.(?:compiled-library(?:-v\\d+)?|library)$/i;\ntype Fetcher = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\nexport interface InstalledLibrary {\n title: string;\n company?: string;\n version?: string;\n namespace?: string;\n path: string;\n sha256: string;\n url?: string;\n}\ninterface LibraryLock {\n version: 1;\n dependencies: Record<string, InstalledLibrary>;\n}\nconst hash = (data: Uint8Array) => createHash(\"sha256\").update(data).digest(\"hex\");\nconst component = (name: string) => {\n if (!name.trim() || /[/\\\\\\0\\r\\n]/.test(name) || name === \".\" || name === \"..\")\n throw new Error(`Invalid library registry component: ${name}.`);\n return encodeURIComponent(name);\n};\nasync function response(url: string, fetcher: Fetcher) {\n const result = await fetcher(url, { signal: AbortSignal.timeout(30_000) });\n if (!result.ok) throw new Error(`Library registry ${result.status}: ${url}`);\n return result;\n}\nexport async function libraryIndex(\n path: string[] = [\"System\"],\n fetcher: Fetcher = fetch,\n): Promise<string[]> {\n const url = `${libraryRegistry}/${path.map(component).join(\"/\")}/index`;\n const result = await response(url, fetcher);\n const text = await result.text();\n if (text.length > 4_000_000 || /<html/i.test(text))\n throw new Error(`Invalid library registry index: ${url}`);\n return text\n .split(/\\r?\\n/)\n .map((s) => s.trim())\n .filter(Boolean);\n}\nexport async function validateLibrary(\n title: string,\n version: string,\n company = \"System\",\n fetcher: Fetcher = fetch,\n) {\n if (!(await libraryIndex([company], fetcher)).includes(title))\n throw new Error(`Unknown CODESYS library ${company}/${title}. Names are case sensitive.`);\n const versions = await libraryIndex([company, title], fetcher);\n if (!versions.includes(version))\n throw new Error(`Unknown version ${version} for ${title}. Available: ${versions.join(\", \")}`);\n const filenames = (await libraryIndex([company, title, version], fetcher)).filter((name) =>\n libraryFile.test(name),\n );\n if (filenames.length !== 1)\n throw new Error(\n `Expected one library payload for ${title} ${version}, received ${filenames.length}.`,\n );\n return {\n filename: filenames[0]!,\n url: `${libraryRegistry}/${[company, title, version, filenames[0]!].map(component).join(\"/\")}`,\n };\n}\nexport async function installLibraries(\n dependencies: Record<string, LibraryDependency>,\n root: string,\n options: { frozen?: boolean; fetcher?: Fetcher } = {},\n) {\n const file = resolve(root, \"tsplc.lock.json\"),\n store = resolve(root, \".tsplc/libraries\");\n let previous: LibraryLock = { version: 1, dependencies: {} };\n try {\n previous = JSON.parse(await readFile(file, \"utf8\"));\n } catch (cause) {\n if (!(cause && typeof cause === \"object\" && \"code\" in cause && cause.code === \"ENOENT\"))\n throw cause;\n }\n if (previous.version !== 1 || !previous.dependencies || typeof previous.dependencies !== \"object\")\n throw new Error(\"Invalid tsplc.lock.json.\");\n const installed: Record<string, InstalledLibrary> = {};\n const fetcher = options.fetcher ?? fetch;\n await mkdir(store, { recursive: true });\n for (const [title, dependency] of Object.entries(dependencies)) {\n component(title);\n const settings = typeof dependency === \"string\" ? { version: dependency } : dependency;\n const locked = previous.dependencies[title];\n const prior = locked ? { ...locked, path: resolve(root, locked.path) } : undefined;\n const same =\n prior !== undefined &&\n prior.namespace === settings.namespace &&\n (\"path\" in settings\n ? prior.url === undefined && prior.path === resolve(root, settings.path)\n : prior.version === settings.version && prior.company === (settings.company ?? \"System\"));\n if (same) {\n try {\n if (hash(await readFile(prior.path)) === prior.sha256) {\n installed[title] = prior;\n continue;\n }\n } catch {\n /* Missing cache can be restored from the exact URL. */\n }\n if (options.frozen) throw new Error(`Locked library ${title} is missing or changed.`);\n } else if (options.frozen) throw new Error(`Dependency ${title} differs from tsplc.lock.json.`);\n if (\"path\" in settings) {\n const path = resolve(root, settings.path);\n if (!libraryFile.test(path))\n throw new Error(`${title}: expected a .library or .compiled-library file.`);\n installed[title] = {\n title,\n path,\n sha256: hash(await readFile(path)),\n ...(settings.namespace ? { namespace: settings.namespace } : {}),\n };\n } else {\n const company = settings.company ?? \"System\";\n const payload = await validateLibrary(title, settings.version, company, fetcher);\n const result = await response(payload.url, fetcher);\n const data = new Uint8Array(await result.arrayBuffer());\n if (!data.length || data.length > 256 * 1024 * 1024)\n throw new Error(`${title}: invalid library payload size.`);\n const sha256 = hash(data);\n // An existing lock pins the payload, even if the registry later changes it.\n if (same && prior.sha256 !== sha256)\n throw new Error(\n `Registry payload changed for locked library ${title} ${settings.version}.`,\n );\n const path = resolve(store, `${sha256}-${basename(payload.filename)}`),\n temp = `${path}.${randomUUID()}.tmp`;\n await writeFile(temp, data, { flag: \"wx\" });\n await rename(temp, path);\n installed[title] = {\n title,\n company,\n version: settings.version,\n path,\n sha256,\n url: payload.url,\n ...(settings.namespace ? { namespace: settings.namespace } : {}),\n };\n }\n }\n if (\n options.frozen &&\n Object.keys(previous.dependencies).some((name) => !Object.hasOwn(dependencies, name))\n )\n throw new Error(\"Removed dependencies differ from tsplc.lock.json.\");\n if (!options.frozen) {\n const temp = `${file}.${randomUUID()}.tmp`;\n const portable = Object.fromEntries(\n Object.entries(installed).map(([title, library]) => [\n title,\n { ...library, path: relative(root, library.path).replaceAll(\"\\\\\", \"/\") },\n ]),\n );\n await writeFile(temp, JSON.stringify({ version: 1, dependencies: portable }, null, 2) + \"\\n\");\n await rename(temp, file);\n }\n return Object.values(installed);\n}\n",
|
|
27
|
+
"import { execFile } from \"node:child_process\";\nimport { mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { promisify } from \"node:util\";\nimport { z } from \"zod\";\nimport { readBuild } from \"./artifacts\";\nimport type { ResolvedConfig } from \"./config\";\nimport { runtimeImage } from \"./docker-build\";\nimport { withWorkerLock } from \"./host/codesys-worker\";\nimport { getApplicationStatus } from \"./runtime-status\";\n\nconst execute = promisify(execFile);\nconst stateSchema = z.object({\n Running: z.boolean(),\n StartedAt: z.iso.datetime({ offset: true }),\n});\n\nconst service = \"plc\";\n\n/** The Docker Compose project of a tsPLC project: `FrameAssembly` runs as `frame-assembly`. */\nexport const runtimeProject = (name: string) =>\n name\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\");\n\n/** The local PLC: named volumes keep its provisioning and the installed application across restarts. */\nexport const runtimeDefinition = (name: string) => ({\n services: {\n [service]: {\n image: runtimeImage,\n platform: \"linux/amd64\",\n hostname: `${runtimeProject(name)}-${service}`,\n init: true,\n ports: [\"127.0.0.1:4840:4840\", \"127.0.0.1:11740:11740\"],\n cap_add: [\"SYS_NICE\", \"IPC_LOCK\"],\n volumes: [\"control-conf:/conf/codesyscontrol\", \"control-data:/data/codesyscontrol\"],\n restart: \"no\",\n },\n },\n volumes: { \"control-conf\": {}, \"control-data\": {} },\n});\n\n/** Deploy the completed boot application to the project's local PLC container. */\nexport const runProject = async (\n config: Pick<ResolvedConfig, \"outDir\" | \"timeouts\">,\n name: string,\n) =>\n withWorkerLock(config, async () => {\n // Validate before stopping anything. A missing receipt includes a failed rebuild.\n const build = await readBuild(config.outDir).catch((cause: unknown) => {\n throw new Error(`No complete build in ${config.outDir}. Run tsplc-build build first.`, {\n cause,\n });\n });\n const definitionDirectory = await mkdtemp(join(tmpdir(), \"tsplc-runtime-\"));\n try {\n const composeFile = join(definitionDirectory, \"compose.yaml\");\n // JSON is valid YAML.\n await writeFile(composeFile, JSON.stringify(runtimeDefinition(name)));\n const docker = (...args: string[]) =>\n execute(\"docker\", args, {\n timeout: config.timeouts.runtime,\n maxBuffer: 8 * 1024 * 1024,\n });\n const compose = (...args: string[]) =>\n docker(\"compose\", \"--project-name\", runtimeProject(name), \"--file\", composeFile, ...args);\n const installer = await readFile(new URL(\"../runtime/install.sh\", import.meta.url), \"utf8\");\n console.log(`Installing ${build.application} in Docker service ${service}`);\n await compose(\"stop\", service);\n // The helper uses the service's volumes without starting its PLC or publishing\n // ports. Its read-only artifact mount is removed with the helper container.\n await compose(\n \"run\",\n \"--rm\",\n \"--no-deps\",\n \"-T\",\n \"--volume\",\n `${dirname(build.output)}:/codesys-build:ro`,\n \"--entrypoint\",\n \"/bin/sh\",\n service,\n \"-c\",\n installer,\n \"codesys-build-install\",\n build.application,\n basename(build.output, \".app\"),\n );\n await compose(\"up\", \"--detach\", \"--no-deps\", service);\n const containers = (await compose(\"ps\", \"--all\", \"--quiet\", service)).stdout\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n if (containers.length !== 1 || !containers[0]) {\n throw new Error(`Expected one container for Compose service ${service}`);\n }\n const container = containers[0];\n const deadline = Date.now() + config.timeouts.runtime;\n while (true) {\n const state = stateSchema.parse(\n JSON.parse((await docker(\"inspect\", \"--format\", \"{{json .State}}\", container)).stdout),\n );\n if (!state.Running) {\n throw new Error(\n `Docker service ${service} exited before the application started. Check docker logs ${container}.`,\n );\n }\n // Use this container start time, not the host clock or an old \"started\" event.\n const { stdout: log } = await docker(\n \"exec\",\n container,\n \"/bin/sh\",\n \"-c\",\n \"if [ -f /data/codesyscontrol/codesyscontrol.log ]; then cat /data/codesyscontrol/codesyscontrol.log; fi\",\n );\n const status = getApplicationStatus(log, build.application, Date.parse(state.StartedAt));\n if (status === \"running\") {\n console.log(`${build.application} is running in ${service}`);\n return { ...build, container };\n }\n if (status === \"failed\" || Date.now() >= deadline) {\n throw new Error(\n `CODESYS did not start ${build.application}. Runtime log:\\n${log.split(\"\\n\").slice(-25).join(\"\\n\")}`,\n );\n }\n await delay(250);\n }\n } finally {\n await rm(definitionDirectory, { force: true, recursive: true });\n }\n });\n",
|
|
28
|
+
"/** Runtime stdout is buffered in Docker. Its log file records start/stop events immediately. */\nexport const getApplicationStatus = (log: string, application: string, startedAt: number) => {\n const event = log\n .split(/\\r?\\n/)\n .reverse()\n .find((line) => {\n const timestamp = Date.parse(line.split(\",\")[0] ?? \"\");\n if (!Number.isFinite(timestamp) || timestamp < startedAt) {\n return false;\n }\n return (\n line.includes(`<app>${application}</app>`) &&\n /\\b(started|stopped|exception|corrupt|failed|denied)\\b/i.test(line) &&\n !line.includes(\"load started\")\n );\n });\n if (!event) {\n return \"pending\";\n }\n return event.includes(`Application [<app>${application}</app>] started`) ? \"running\" : \"failed\";\n};\n",
|
|
29
|
+
"import { readdir, readFile } from \"node:fs/promises\";\nimport { basename, resolve } from \"node:path\";\nimport type { ResolvedConfig } from \"./config\";\nimport { type ObjectKind, type ParsedSource, parseSource } from \"./st/parse\";\nimport { bindStructuredTextIo } from \"./io.ts\";\n\nexport type SourceObject = ParsedSource & {\n source: string;\n folder: string[];\n children: SourceObject[];\n};\ntype Files = {\n combined: string[];\n declaration: string[];\n implementation: string[];\n};\nconst prefixes: Record<string, ObjectKind> = {\n FB: \"function_block\",\n PRG: \"program\",\n FUN: \"function\",\n F: \"function\",\n I: \"interface\",\n ST: \"dut\",\n E: \"dut\",\n T: \"dut\",\n U: \"dut\",\n GVL: \"gvl\",\n};\nconst childFolders: Record<string, ObjectKind> = {\n methods: \"method\",\n properties: \"property\",\n actions: \"action\",\n};\nconst canOwn = (kind: ObjectKind) =>\n [\"program\", \"function_block\", \"interface\", \"property\"].includes(kind);\nconst assertUnique = (objects: SourceObject[], scope: string) => {\n const seen = new Map<string, string>();\n for (const object of objects) {\n const key = object.name.toLowerCase();\n const previous = seen.get(key);\n if (previous) {\n throw new Error(\n `Duplicate IEC name ${object.name} in ${scope}: ${previous} and ${object.source}`,\n );\n }\n seen.set(key, object.source);\n assertUnique(object.children, `${scope}.${object.name}`);\n }\n};\n\nconst readUnit = async (\n name: string,\n files: Files,\n role?: ObjectKind,\n interfaceMember = false,\n): Promise<ParsedSource & { source: string }> => {\n if (!/^[A-Za-z_][A-Za-z_0-9]*$/.test(name)) {\n throw new Error(`Invalid IEC object name: ${name}`);\n }\n for (const [part, candidates] of Object.entries(files)) {\n if (candidates.length > 1) {\n throw new Error(`Ambiguous ${part} for ${name}: ${candidates.join(\", \")}`);\n }\n }\n const combined = files.combined[0];\n const declaration = files.declaration[0];\n const implementation = files.implementation[0];\n if (combined && (declaration || implementation)) {\n throw new Error(`Both combined and split sources exist for ${name}`);\n }\n const path = combined ?? declaration ?? implementation;\n if (!path) {\n throw new Error(`Missing source for ${name}`);\n }\n if (role === \"action\") {\n if (!combined) {\n throw new Error(`Actions use one implementation-only .st file: ${path}`);\n }\n return {\n kind: \"action\",\n name,\n declaration: \"\",\n implementation: await readFile(combined, \"utf8\"),\n source: combined,\n };\n }\n if (role === \"get\" || role === \"set\") {\n if (!combined) {\n throw new Error(`Property accessors use one .st file: ${path}`);\n }\n const body = await readFile(combined, \"utf8\");\n const header = `METHOD ${name}\\n`;\n const parsed = parseSource(`${header}${body}\\nEND_METHOD`, {\n filename: combined,\n });\n return {\n ...parsed,\n kind: role,\n name,\n declaration: parsed.declaration.slice(header.length),\n source: combined,\n };\n }\n if (!combined && !declaration) {\n throw new Error(`Missing declaration for ${path}`);\n }\n const sourcePath = combined ?? declaration ?? path;\n const parsed = parseSource(await readFile(sourcePath, \"utf8\"), {\n filename: sourcePath,\n name,\n declarationOnly: !combined || interfaceMember,\n });\n if (parsed.name.toLowerCase() !== name.toLowerCase()) {\n throw new Error(`Source name ${name} does not match declaration ${parsed.name}: ${sourcePath}`);\n }\n if (role && parsed.kind !== role) {\n throw new Error(`Expected ${role}, found ${parsed.kind}: ${sourcePath}`);\n }\n if (!role && [\"method\", \"property\"].includes(parsed.kind)) {\n throw new Error(`Child object has no enclosing POU: ${sourcePath}`);\n }\n const prefix = /^([A-Z]+)_/.exec(name.toUpperCase())?.[1];\n if (!role && prefix && prefixes[prefix] && prefixes[prefix] !== parsed.kind) {\n throw new Error(`Prefix ${prefix}_ conflicts with ${parsed.kind}: ${sourcePath}`);\n }\n const declarationOnly =\n [\"dut\", \"gvl\", \"interface\", \"property\"].includes(parsed.kind) || interfaceMember;\n if (declarationOnly && implementation) {\n throw new Error(`This object has no implementation: ${implementation}`);\n }\n if (!combined && !declarationOnly && !implementation) {\n throw new Error(`Missing implementation for ${sourcePath}`);\n }\n return {\n ...parsed,\n ...(implementation ? { implementation: await readFile(implementation, \"utf8\") } : {}),\n source: sourcePath,\n };\n};\n\n/** Folder placement organizes the IDE; it never changes IEC names or execution order. */\nexport const loadSources = async (\n config: Pick<ResolvedConfig, \"sourceDir\" | \"entry\" | \"io\" | \"tasks\">,\n) => {\n const objects: SourceObject[] = [];\n const visit = async (\n directory: string,\n folder: string[],\n parent?: SourceObject,\n role?: ObjectKind,\n ): Promise<void> => {\n const entries = (await readdir(directory, { withFileTypes: true })).sort((a, b) =>\n a.name.localeCompare(b.name, \"en\"),\n );\n const groups = new Map<string, { name: string; files: Files }>();\n for (const entry of entries) {\n if (entry.isSymbolicLink()) {\n throw new Error(`Source symlinks are not supported: ${resolve(directory, entry.name)}`);\n }\n if (!entry.isFile() || !/\\.st$/i.test(entry.name)) {\n continue;\n }\n const stem = entry.name.slice(0, -3);\n const suffix = /^(.*)\\.(declaration|implementation)$/.exec(stem);\n const generic = [\"source\", \"declaration\", \"implementation\"].includes(stem);\n const name = generic ? basename(directory) : (suffix?.[1] ?? stem);\n const section = suffix?.[2] ?? stem;\n const part = section === \"declaration\" || section === \"implementation\" ? section : \"combined\";\n const key = name.toLowerCase();\n const group = groups.get(key) ?? {\n name,\n files: { combined: [], declaration: [], implementation: [] },\n };\n group.files[part].push(resolve(directory, entry.name));\n groups.set(key, group);\n }\n const units: SourceObject[] = [];\n const ownKey = basename(directory).toLowerCase();\n // Read an object's own source before its Get/Set files, which have no POU header.\n const ordered = [...groups].sort(([a], [b]) => Number(b === ownKey) - Number(a === ownKey));\n for (const [key, { name, files }] of ordered) {\n const ownProperty = units.find(\n (unit) => unit.kind === \"property\" && unit.name.toLowerCase() === ownKey,\n );\n const accessor = ownProperty && (key === \"get\" || key === \"set\") ? key : undefined;\n const unit: SourceObject = {\n ...(await readUnit(\n accessor ? `${accessor[0]?.toUpperCase()}${accessor.slice(1)}` : name,\n files,\n accessor ?? role,\n parent?.kind === \"interface\",\n )),\n folder: parent ? [] : folder,\n children: [],\n };\n if (accessor && ownProperty) {\n if (parent?.kind === \"interface\") {\n throw new Error(`Interface properties cannot implement accessors: ${unit.source}`);\n }\n ownProperty.children.push(unit);\n } else {\n units.push(unit);\n if (parent) {\n parent.children.push(unit);\n } else {\n objects.push(unit);\n }\n }\n }\n const own = units.find((unit) => unit.name.toLowerCase() === ownKey && canOwn(unit.kind));\n if (own && !parent) {\n own.folder = folder.slice(0, -1);\n }\n for (const entry of entries.filter((entry) => entry.isDirectory())) {\n const childRole = childFolders[entry.name];\n if (own && childRole) {\n if (own.kind === \"property\" || (own.kind === \"interface\" && childRole === \"action\")) {\n throw new Error(`Unsupported ${entry.name} under ${own.name}`);\n }\n await visit(resolve(directory, entry.name), [], own, childRole);\n } else if (parent) {\n await visit(resolve(directory, entry.name), [], parent, role);\n } else {\n await visit(resolve(directory, entry.name), [...folder, entry.name]);\n }\n }\n };\n await visit(resolve(config.sourceDir), []);\n assertUnique(objects, \"Application\");\n if (config.io) bindStructuredTextIo(objects, config.io);\n const entry = objects.find((object) => object.source === resolve(config.entry));\n if (!entry) {\n throw new Error(`Entry is not a discovered source: ${config.entry}`);\n }\n if (entry.kind !== \"program\") {\n throw new Error(`Entry must be a PROGRAM: ${config.entry}`);\n }\n if (config.tasks) {\n const programs = new Set(\n objects.filter((object) => object.kind === \"program\").map((object) => object.name),\n );\n for (const task of config.tasks)\n for (const program of task.programs)\n if (!programs.has(program))\n throw new Error(`Task ${task.name} references an undiscovered PROGRAM ${program}`);\n }\n return { entry: entry.name, objects };\n};\n"
|
|
30
|
+
],
|
|
31
|
+
"mappings": "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",
|
|
32
|
+
"debugId": "C865C1ABFC6D750A64756E2164756E21",
|
|
33
|
+
"names": []
|
|
34
|
+
}
|