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

@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

  1. Quick start (using the npm package)
  2. In-depth overview
    1. Analyze a form
    2. Generate forms from a lemma
    3. Use parallel contexts
    4. Raw access and cleanup
  3. Other installation options
    1. Acquire components separately
    2. Build the Node-API addon
  4. Native library and runtime data
    1. Acquire stem data
    2. Acquire the native library
    3. Language and data coverage
  5. Supported environments
  6. Documentation
  7. Local checks
  8. 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/node

Package 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 perseids

The 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.js

The 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-gener

In-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() and generateRaw() 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-data

Applications 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_node

If 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-data

Choose --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-data

The 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-native

The 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 test

License

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.