npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

codesys-build

v0.2.0

Published

Build CODESYS applications from domain-organized Structured Text sources.

Readme

codesys-build

Build CODESYS applications from Structured Text files organized by domain. Author complete ST objects or explicit declaration/implementation pairs, select an entry program in TypeScript, and compile against an existing CODESYS project template.

This package uses the CODESYS scripting interface. It does not use the paid File-Based Storage add-on. By default the IDE build runs in Docker, containing Bun, Wine 11.19 and CODESYS 3.5.22.30. The npm CLI requires Node and Docker on the host. Target device packages, libraries and licenses must still match the project template. Local Windows/Wine installations remain available through explicit codesys settings.

The independent native path targets CODESYS Virtual Control Linux ARM64 4.22. It translates ST with an independently implemented frontend, Clang and LLD; Wine, the IDE, vendor compiler assemblies and a prebuilt application are not required. The actual 42-object frame-assembly app has passed OPC UA-backed end-to-end simulation and all 28 PLC integration tests with this path. See the native compiler guide for setup and limits.

The legacy template/IDE workflow below remains available for other targets.

Install

Install with npm using Node 22.18+ on the 22.x line, or Node 24.3+:

npm install --save-dev codesys-build
npx codesys-build configure

configure prepares the builder image once using the Docker recipe included in the npm package. It downloads, verifies and installs CODESYS 64 3.5.22.30 and its prerequisites automatically, assuming acceptance of the vendor license and readme. No EXE, account credentials, Bun or Wine installation is needed on the host. Image preparation needs internet access and several gigabytes of space; subsequent builds run without network access. The image matches the Docker server's architecture and includes FEX to run Intel Wine on ARM64. See Docker builds.

The command works before creating a project config. When a config exists, it uses that config's docker.image; --config path/to/config.ts selects another config. Docker caches completed installation steps for repeated setup. Create the project config below, then run:

npx codesys-build check
npx codesys-build build

First project

Create codesys-build.config.ts:

import { defineConfig } from "codesys-build";

export const config = defineConfig({
	template: "templates/base.project",
	entry: "src/Main.st",
	task: "MainTask",
});

The template must have an active Application and an existing task named MainTask. Its device, library references, cycle interval, priority and watchdog remain configured in CODESYS. During the build, that task's program-call list is replaced with the selected entry. Other tasks retain their configuration and calls. An optional complete tasks plan instead sets cyclic timing, priorities and ordered PROGRAM calls, and removes unspecified tasks from the private build copy; see configuration.

Create src/Main.st:

PROGRAM Main
VAR
	Cycles : UDINT;
END_VAR

Cycles := Cycles + 1;
END_PROGRAM

Add package scripts:

{
	"scripts": {
		"configure:plc": "codesys-build configure",
		"check:plc": "codesys-build check",
		"build:plc": "codesys-build build",
		"open:plc": "codesys-build open",
		"stop:plc": "codesys-build stop-worker"
	}
}

Run them with npm run check:plc and npm run build:plc. check validates source envelopes, file layout, names and entry selection. It does not typecheck ST or prove that CODESYS can compile it. build runs the actual compiler and verifies its diagnostics and artifacts. open and worker commands require a local codesys configuration; Docker builds stop their worker and remove the container on exit.

For a local Wine installation:

import { homedir } from "node:os";
import { join } from "node:path";
import { defineConfig } from "codesys-build";

const prefix = join(homedir(), ".wine.codesys");
export const config = defineConfig({
	codesys: {
		executable: join(prefix, "drive_c/CODESYS-3.5.22.30/CODESYS/Common/CODESYS.exe"),
		profile: "CODESYS V3.5 SP22 Patch 3",
		wine: { prefix, binary: "wine", pathBinary: "winepath" },
	},
	template: "templates/base.project",
	entry: "src/Main.st",
});

These are configuration values, not environment-variable names. Change installation paths and profile to match your machine. No .env file is required. OS process settings such as PATH and DISPLAY are inherited so the installed tools can run.

Source layout

src/
  Main.st
  transport/
    FB_Conveyor/
      source.st
      methods/
        SetEnabled.st
      properties/
        IsRunning/
          declaration.st
          get.st
      actions/
        ResetCounter.st
    ST_ConveyorState.st
  framing/
    PRG_Framing/
      declaration.st
      implementation.st

Combined executable objects include their PROGRAM / FUNCTION_BLOCK / FUNCTION / METHOD header and matching END_*. A folder's combined source may be source.st or <object-name>.st. A standalone <object-name>.st is also supported.

All these split layouts are accepted:

FB_Motor/declaration.st                  + FB_Motor/implementation.st
FB_Motor/FB_Motor.declaration.st         + FB_Motor/FB_Motor.implementation.st
FB_Motor/declaration.st                  + FB_Motor/FB_Motor.implementation.st
FB_Motor/FB_Motor.declaration.st         + FB_Motor/implementation.st
any-domain/FB_Motor.declaration.st       + any-domain/FB_Motor.implementation.st

There is no precedence rule for duplicate sources: two implementations for one object, or a combined file alongside a split pair, are errors. An empty implementation file is valid. A missing implementation file is not.

The source declaration determines the kind and IEC name. Recognized prefixes (FB_, PRG_, F_/FUN_, I_, ST_/E_/T_/U_, GVL_) are checked for consistency when present. Plain type filenames and existing globals such as LineIO.st remain valid. GVLs have no named header, so their filename determines their CODESYS name. Folder names organize the IDE; they do not create IEC namespaces. Application object names must remain unique, ignoring case.

See source conventions for methods, properties, actions, interfaces and parsing limits.

Commands and artifacts

codesys-build check
codesys-build build
codesys-build run
codesys-build open
codesys-build open templates/local.project
codesys-build launch-worker
codesys-build stop-worker
codesys-build build --config path/to/codesys-build.config.ts

The default config path is relative to the working directory. Paths inside a config are relative to that config's directory. The optional project argument to open is relative to the working directory.

Each build replaces the project, boot application and receipt at the same paths. Docker diagnostics are under .codesys/docker/job/.codesys/; a local IDE uses the layout below:

build/
  Application.project        # Open with codesys-build open
  runtime/Application.app    # Boot application
  runtime/Application.crc    # Matching checksum
  build.json                 # Completion receipt, published last
  .codesys/
    build/                   # Latest request, template snapshot and diagnostics
    worker/                  # Compiler scripts, log and private working project
    editor/                  # Latest interactive IDE launcher and log
    session.json

outDir controls this directory. Builds reuse these locations instead of retaining run-* or session directories. A failed compilation invalidates build.json, so run cannot silently deploy an earlier build. The previous published project remains available for inspection. build does not change the runtime.

To run on CODESYS Virtual Control for Linux in Docker, configure the Compose service:

runtime: { composeFile: "compose.yaml", service: "plc" }

Then run codesys-build build followed by codesys-build run. The latter uses the completed boot files without launching the IDE: it stops only the selected service, installs the matching .app and .crc, starts the service, and waits for the application's start event in the current runtime log. It does not start a UI, OPC UA bridge, or engineering gateway. See running in Docker and the included Compose example.

With local codesys settings, one background CODESYS worker is retained per output directory. It reuses the loaded project for text-only changes and reloads the template when object membership, folders, entry selection, an explicit task plan or template contents change. Source-owned objects replace their template copies, including child objects removed from source. Failed projects are discarded from the worker's cache. Docker builds start and stop a worker inside each temporary container.

See configuration, operation and troubleshooting, and the frame-assembly example.

Package development

bun install --frozen-lockfile
bun test ./src ./tests
bun run test:python
bun run tsc
bun run check

Unit tests cover parsing, discovery and configuration. CLI tests use a fake CODESYS executable to exercise real subprocesses, locking, worker reuse, failures and artifacts. Python tests replace only the CODESYS API. Those tests do not substitute for the real compiler verification recorded with the example.

The parser audit records checks against 5,068 real source objects, seeded adversarial tests, compiler probes and known boundary ambiguities. Normal CODESYS application compilation covers reachable POUs; unused implementations can still contain compiler errors.

Independent native builds

Use defineNativeConfig and build-native (or buildNativeProject) to compile without vendor compiler tools. check and run also accept native configuration. Python 3.10+, Bun, Clang and LLVM LLD are required. Indexed array symbols, timers and the frame-assembly app's OPC UA contract are verified. See the native compiler guide for tested language coverage, PLCopen import, downloadable source libraries, open-source math support and remaining limitations.

Download original library files and a pinned dependency catalog with codesys-build fetch-libraries --request libraries.json --output libraries, then verify its captured evidence offline with codesys-build verify-libraries --lock libraries/native-library-lock.json. See native library support for request format, version policy, supported containers and unresolved placeholder behavior.

An original binary .project can supply its saved ST sources, application name, cyclic task and exact library redirections directly:

import { defineNativeConfig } from "codesys-build";

export const config = defineNativeConfig({
	projectSource: { path: "original.project", sha256: "<64 hex characters>" },
	task: "MainTask",
	libraryCatalog: [
		{ path: "Standard.compiled-library-v3", sha256: "<64 hex characters>" },
	],
	symbols: true,
});

Run codesys-build build-native --python /path/to/python --linker /path/to/ld.lld. No extracted ST directory is required. The completion receipt preserves the saved application name, with runtime/<application>.app and matching .crc artifacts. runtime/source.json retains the original source bodies and selected task; runtime/project-intake.json records the original task/library evidence and all excluded tasks, device and visualization services. This path builds one supported saved cyclic user ST task; HMI, device configuration and physical I/O are outside its scope. Missing dependencies or unsupported saved scheduling fail explicitly. See binary project configuration.