@libmorpheus/node
v0.1.1
Published
Node.js binding for the libmorpheus morphological analyzer
Readme
libmorpheus for Node.js
libmorpheus modernizes the Morpheus
morphological analyzer for Ancient Greek and Latin. It turns the historical C
programs into an installable C17 shared library with a stable, opaque ABI and a
typed Node.js binding.
This package loads the
libmorpheus shared library
through a small Node-API addon. It exposes normalized Greek and Latin analysis
plus experimental Greek lemma generation. Native results are copied into owned
JavaScript objects before their C allocations are released.
Summary
- Quick start (using the npm package)
- In-depth overview
- Other installation options
- Native library and runtime data
- Supported environments
- Documentation
- Local checks
- License
Quick start (using the npm package)
The simplest installation needs Node.js 20 or later and no C toolchain. The prebuilt Node-API addons and native archives currently support Linux x86-64 glibc, Linux aarch64 glibc, and macOS arm64. Install the binding:
npm install @libmorpheus/nodePackage installation runs no scripts. Acquire the matching native library and the Perseids dataset for Greek and Latin analysis with the explicit setup command:
npx libmorpheus-setup --dataset perseidsThe output directories must not already exist and must not overlap; the command
refuses to overwrite an installation or dataset. It creates
./morpheus-native and ./morpheus-data by default.
Create app.js:
import {
MorpheusLanguage,
MorpheusLibrary,
MorpheusOption,
} from "@libmorpheus/node";
import { nativeLibraryPath } from "@libmorpheus/node/native";
import { resolve } from "node:path";
const library = new MorpheusLibrary(
nativeLibraryPath("./morpheus-native"),
);
const context = library.createContext(
resolve("./morpheus-data"),
MorpheusLanguage.Greek,
);
try {
const analyses = await context.analyze(
"a)/nqrwpos",
MorpheusOption.StrictCase,
);
for (const analysis of analyses) {
console.log(analysis.lemma, analysis.partOfSpeech);
}
} finally {
await context.close();
library.close();
}Run it normally:
node app.jsThe binding itself performs no network access and needs no environment
variables at runtime. Applications may instead pass paths from their own
configuration, including MORPHEUS_LIBRARY and MORPHEUS_STEMLIB.
For Greek analysis and experimental generation, choose the Alpheios dataset and build its validated index during setup:
npx libmorpheus-setup --dataset alpheios --with-generIn-depth overview
Analyze a form
import {
MorpheusError,
MorpheusLanguage,
MorpheusLibrary,
MorpheusOption,
} from "@libmorpheus/node";
const library = new MorpheusLibrary("/usr/local/lib/libmorpheus.so");
const context = library.createContext(
"/path/to/stemlib",
MorpheusLanguage.Greek,
);
try {
const analyses = await context.analyze(
"a)/nqrwpos",
MorpheusOption.StrictCase,
);
console.log(analyses[0].partOfSpeech); // "noun"
console.log(analyses[0].grammaticalNumber); // "singular"
console.log(analyses[0].grammaticalCases); // ["nominative"]
} catch (error) {
if (error instanceof MorpheusError) {
console.error(`Morpheus status ${error.status}: ${error.message}`);
} else {
throw error;
}
} finally {
await context.close();
library.close();
}analyze() returns stable English identifiers, arrays for combinable masks, and
null for inapplicable scalar values. It preserves all analyses. A generic
stemlib indecl class remains "unknown" because it does not identify a
lexical category. An empty dialect array means no recorded restriction.
Options are bigint bit flags and may be combined with |. For example,
strict case plus accent-insensitive fallback is:
const options = MorpheusOption.StrictCase |
MorpheusOption.IgnoreAccents;
const analyses = await context.analyze("a)/nqrwpos", options);Passing no option uses the binding's default analysis behavior. See the native option table before enabling specialized modes.
MorpheusOption.HqDictionary requires both HQ index files. If they are absent,
the promise rejects with MorpheusStatus.StemlibError before native analysis.
Generate forms from a lemma
[!WARNING]
generate()andgenerateRaw()are experimental. Their automated differential, isolation, failure, portability, and sanitizer coverage is extensive, but sufficient real-world use is still required before this qualification can be removed.
import {
MorpheusDialect,
MorpheusError,
MorpheusLanguage,
MorpheusLibrary,
MorpheusNumber,
MorpheusStatus,
} from "@libmorpheus/node";
const library = new MorpheusLibrary("/usr/local/lib/libmorpheus.so");
const context = library.createContext(
"/path/to/stemlib",
MorpheusLanguage.Greek,
);
try {
const duals = await context.generate("lo/gos", {
number: MorpheusNumber.Dual,
dialect: MorpheusDialect.Attic,
resultLimit: 256,
});
for (const form of duals) {
console.log(form.surface, form.grammaticalCases);
}
} catch (error) {
if (
error instanceof MorpheusError &&
error.status === MorpheusStatus.ResultLimitExceeded
) {
console.error("Increase the explicit result limit for this paradigm");
} else {
throw error;
}
} finally {
await context.close();
library.close();
}generate() is nonblocking and accepts typed filters for part of speech,
dialect, region, person, number, gender, case, tense, mood, voice, and degree.
It preserves dialect masks, duals, duplicate surfaces, and multiple indexed
interpretations unless filters remove them. excludeDuals is available when
dual forms are unwanted. The default native limit is 4,096 and the explicit
hard maximum is 65,536.
Use parallel contexts
One context deliberately queues analysis and generation calls because the native context is stateful. Create separate contexts to perform independent work concurrently on Node's asynchronous worker pool:
const library = new MorpheusLibrary("/usr/local/lib/libmorpheus.so");
const first = library.createContext(stemlib, MorpheusLanguage.Greek);
const second = library.createContext(stemlib, MorpheusLanguage.Greek);
try {
const [analyses, forms] = await Promise.all([
first.analyze("a)/nqrwpos"),
second.generate("lo/gos"),
]);
} finally {
await Promise.all([first.close(), second.close()]);
library.close();
}The actual speedup depends on the workload and machine. Reuse warm contexts; the generation index is loaded lazily once per context.
Raw access and cleanup
Use analyzeRaw() and generateRaw() for ABI inspection and low-level tools.
They return numeric normalized traits, structSize, the complete 11-byte public
morphology vector, and a numeric truncation mask. The semantic methods return
named morphology flags and truncated fields.
Close contexts before their parent library. context.close() waits for queued
work and is idempotent. library.close() is synchronous and rejects while any
child context remains open. A try/finally block provides deterministic
cleanup, including when an operation rejects.
Other installation options
Acquire components separately
The combined setup command is a convenience wrapper. The same verified native runtime and datasets can be acquired independently:
npx libmorpheus-native --output ./morpheus-native
npx libmorpheus-data \
--dataset perseids \
--output ./morpheus-dataApplications that provision their own compatible runtime or stemlib do not need to run either command. The npm package contains neither component and has no post-install hook.
Build the Node-API addon
Configure a source checkout with a Node.js installation that provides
node_api.h:
cmake -S . -B build/node -G Ninja \
-DMORPHEUS_BUILD_NODE_BINDING=ON
cmake --build build/node --target libmorpheus_nodeIf CMake cannot infer the header location, set
MORPHEUS_NODE_INCLUDE_DIR=/path/to/node/include/node. Point the JavaScript
facade at the result during development:
export MORPHEUS_NODE_ADDON="$PWD/build/node/node/libmorpheus_node.node"MORPHEUS_NODE_ADDON is a development override. Published applications should
normally use the optional platform package selected by npm.
Native library and runtime data
The binding needs a Node-API addon, a native libmorpheus library, and a
compatible stemlib. The npm installation supplies only the first component.
| Component | Included by npm install | What to do |
| --- | :---: | --- |
| JavaScript facade and types | Yes | Import @libmorpheus/node. |
| Platform Node-API addon | Yes, as an optional dependency | Do not omit optional dependencies. |
| Native libmorpheus runtime | No | Run libmorpheus-setup or libmorpheus-native. |
| Linguistic stem data | No | Run libmorpheus-setup or libmorpheus-data. |
Binding and runtime versions are independent. Binding 0.1.1 currently
acquires native runtime 0.3.2 and requires C ABI 2. The main module exports
MORPHEUS_NODE_VERSION; the /native module exports
MORPHEUS_NATIVE_VERSION and MORPHEUS_NATIVE_ABI_VERSION for tooling.
Acquire stem data
For Greek and Latin analysis, acquire the Perseids dataset:
npx libmorpheus-data \
--dataset perseids \
--output ./morpheus-dataChoose --dataset alpheios instead for the Greek-only reference dataset. Add
--with-gener to build its experimental Greek generation index:
npx libmorpheus-data \
--dataset alpheios \
--with-gener \
--output ./morpheus-greek-dataThe command verifies pinned sources, the complete selected file tree, the upstream license, and—when requested—the generated index. It refuses to overwrite an existing directory and writes a provenance receipt. See the complete runtime-data guide.
Acquire the native library
Install the matching native release without Git or a C toolchain:
npx libmorpheus-native --output ./morpheus-nativeThe command selects the declared native release for the current platform,
verifies its SHA-256 digest, safely extracts it into a new directory, and writes
MORPHEUS-NATIVE.json. Use the exported helper to avoid platform-specific
filenames:
import { MorpheusLibrary } from "@libmorpheus/node";
import { nativeLibraryPath } from "@libmorpheus/node/native";
const library = new MorpheusLibrary(
nativeLibraryPath("./morpheus-native"),
);Language and data coverage
The operation and selected dataset together determine language coverage:
| Operation or dataset | Ancient Greek | Latin | Additional requirement |
| --- | :---: | :---: | --- |
| analyze() | Yes | Yes | A stemlib for the selected language. |
| generate() | Yes | No | Alpheios data prepared with gener.index. |
| Perseids | Yes | Yes | No |
| Alpheios | Yes | No | Pass --with-gener for generation. |
See the stem-library inventory for dataset origins and repository locations.
Supported environments
The package requires Node.js 20 or later and uses ESM. Prebuilt addon and native runtime acquisition currently support:
| Operating system | Architecture | C library | | --- | --- | --- | | Linux | x86-64 | glibc | | Linux | aarch64 | glibc | | macOS | arm64 | system |
On Linux, musl environments are rejected rather than loading an incompatible
binary. npm optional dependencies must remain enabled. There is no Windows or
macOS x86-64 prebuilt package in version 0.1.1.
Documentation
The npm package exposes the main binding and independently importable
@libmorpheus/node/setup, @libmorpheus/node/data, and
@libmorpheus/node/native entrypoints. Their TypeScript declarations ship with
the package.
| Topic | Document | | --- | --- | | Native ABI, ownership, and options | Public API | | Runtime and dataset acquisition | Runtime data | | AGPL/MPL file boundary | Licensing guide | | Source and dataset lineage | Provenance | | Available stem libraries | Stem libraries | | Supported platforms | Portability | | Release archives and qualification | Releasing |
Local checks
Build the library, Node-API addon, and small differential generation index before running the binding tests:
cmake --preset dev -DMORPHEUS_BUILD_NODE_BINDING=ON
cmake --build --preset dev --target \
morpheus libmorpheus_node morpheus_gener_index_builder
build/dev/morpheus_gener_index_builder \
stemlib/gener.index test/generation-service-source.txt
MORPHEUS_NODE_ADDON="$PWD/build/dev/node/libmorpheus_node.node" \
MORPHEUS_LIBRARY="$PWD/build/dev/libmorpheus.so" \
MORPHEUS_STEMLIB="$PWD/stemlib" \
npm --prefix bindings/js/node testLicense
The Node.js binding, Node-API adapter, and acquisition tooling are licensed under AGPL-3.0-or-later. The package contains neither the native runtime nor linguistic stem data.
The acquisition tooling includes an internal data preparer built from MPL-2.0-covered Morpheus code and the MIT-licensed Emscripten runtime. These components retain their own licenses; they do not change the license of the binding itself. See the package notice and the project's licensing guide for the precise file-level boundary.
