This repository contains the openHAB JavaScript library (openhab-js), a high-level pure JavaScript API for interacting with openHAB Core's Java APIs. It is designed to be used in the openHAB JavaScript Scripting add-on, running in a GraalVM JavaScript environment.
Key Resources:
The repository is organized as follows:
repo root folder
├── src/ # Core library source code (CommonJS)
│ ├── actions/ # Built-in actions and notification builders
│ ├── items/ # Item management, persistence, semantics, metadata
│ ├── rules/ # Rule, condition, trigger, and operation builders
│ ├── index.js # Main entrypoint using lazy getters
│ ├── time.js # Date/time utilities (wraps @js-joda/core)
│ └── globals.d.ts # Compiler-facing global types
├── test/ # Tests and mocks
│ ├── openhab.mock.js # Java host environment stubs
│ ├── *.spec.js # Jest test files
│ └── *.test.js # Mocha test files (Legacy)
├── build/ # Build, bundler, and type config
│ ├── tsconfig.json # TypeScript declaration generation
│ ├── webpack.config.js # Primary UMD module bundling
│ └── @globals-webpack.config.js # Global namespace injection config
├── dist/ # Built Webpack bundles for openHAB add-on
├── types/ # Generated .d.ts declaration files
└── docs/ # JSDoc output (deployed to GitHub Pages)
openhab-js runs in the openHAB JavaScript Scripting add-on environment, which is powered by GraalVM JavaScript running inside a Java host.
This environment has specific restrictions:
Warning
- No Node.js core libraries: Standard Node.js modules (such as
node:http,fs,path, etc.) are not available. Only pure ECMAScript and bundled dependencies (like@js-joda/core) can be used. - Synchronous Execution Only: The runtime environment is synchronous. Promises,
async/awaitfunctions, and asynchronous timers (setTimeout,setInterval) are not supported and must not be used in the core code.
-
The recommended Node.js version is defined in .nvmrc. It is recommended to use a version manager such as
nvm(runnvm use). -
Install dependencies using npm:
npm install
-
Linting:
-
Lint files in
src/using ESLint (with JavaScript Standard Style):npm run lint
-
Auto-fix style issues:
npm run lint:fix
-
-
Testing:
-
Run the full test suite (Mocha + Jest):
npm test
-
-
Bundling:
-
Bundle the source with Webpack into the
dist/directory:npm run webpack
-
-
Type Declarations:
-
Generate
.d.tstype declarations undertypes/:npm run types
-
Verify the generated type definitions for syntax and compilation:
npm run types:test
-
-
Documentation:
-
Build the HTML JSDoc documentation under
docs/:npm run docs
-
-
Full Production Build:
-
Perform tests, bundle, generate types, and compile JSDoc:
npm run build
-
- Write Jest tests: All new unit tests should be written using Jest and placed in the test/ folder (or subfolders) with the extension
*.spec.js. - Legacy Mocha tests: Legacy test files with the extension
*.test.jsrun under Mocha. These are still present in the repository but will be migrated or removed in the future. Avoid adding new Mocha tests. - Test Mocks: Ensure that tests stub out Java-specific hosts (like
@runtime) using the provided mock modules under thetest/directory.
This section documents the architecture and constraints for type definition generation and global type resolution in openhab-js.
There is a strict separation between the globals used during type generation (npm run types) and those exposed to public package consumers:
- Purpose: Used only by
tscwhen generating.d.tsfiles from the JS source. - Location: src/globals.d.ts
- Configuration: Included in build/tsconfig.json.
- Key Constraint: Because JS files are CommonJS modules exporting constructor values,
src/globals.d.tsmust useInstanceType<typeof import(...)>to extract class instance types. Otherwise, the compiler will fail to compile.
- Purpose: Used by external library consumers (and VS Code) when importing
openhab-js. - Location: types/openhab-js.d.ts
- Configuration: Exposed via
"types"inpackage.json. - Key Constraint: Because the generated declaration files under
types/are true TS modules exporting actual class/type definitions, this file must not useInstanceType<typeof ...>for classes. Instead, it must use direct type imports (e.g.import('./items/items').Item) to allow editor engines like VS Code to resolve class member autocompletion instantly.
- The
types/output directory must never be included in the compilation input patterns/includearray of build/tsconfig.json. - If a file in the input graph imports or references files under
types/during build time,tscloads them as compilation inputs. Whentscthen attempts to output the generated declarations totypes/, it raiseserror TS5055: Cannot write file because it would overwrite input file. - To avoid this, always keep
src/globals.d.tsimporting directly from the source.jsfiles using relative paths withinsrc/(e.g.,./items/itemsinstead of../types/items/items).
- By default, without strict null checks, union types containing
null(e.g.,number | nullorQuantity | null) collapse into the base type (e.g.,number,Quantity) during declaration generation. "strictNullChecks": trueis enabled in build/tsconfig.json to preserve union type definitions in the generated.d.tsoutput.