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

polish-engine

v2.0.1

Published

A typed expression engine using postfix notation, normalized results, complex numbers, and calculation steps.

Downloads

225

Readme

Polish Engine

npm CI License

Polish Engine is a small TypeScript library that parses infix mathematical expressions, converts them to postfix notation (RPN), and evaluates them. It supports variables, normalized real and complex results, and optional calculation steps suitable for educational tools, calculators, and math-oriented interfaces.

It is an expression evaluator, not a computer algebra system: it evaluates numeric expressions but does not perform symbolic simplification, differentiation, integration, or equation solving.

Installation

npm install polish-engine

Polish Engine is published as an ES module and includes TypeScript declarations.

Quick start

import { polishEngine } from "polish-engine";

const engine = new polishEngine();
const output = engine.evaluate("2 + 3 * 4", { steps: false });

console.log(output.display); // "14"

Evaluation modes

evaluate(expression, options) uses normalized output and includes calculation steps by default.

| Options | Return value | | --- | --- | | omitted, or { steps: true, normalize: true } | { result: NormalizedValue, steps: NormalizedStep[] } | | { steps: false } | NormalizedValue | | { normalize: false } | { result: RawValue, steps: Step[] } | | { steps: false, normalize: false } | RawValue |

Basic evaluation

engine.evaluate("(2 + 3) * 4", { steps: false });
// { type: "real", value: 20, display: "20" }

Variables

Pass variables inside the options object:

engine.evaluate("2x + 1", {
  variables: { x: 3 },
  steps: false
});
// { type: "real", value: 7, display: "7" }

The v1-compatible variables object is also supported. It uses the v2 defaults, including steps and normalization:

engine.evaluate("2x + 1", { x: 3 });
// { result: { type: "real", value: 7, display: "7" }, steps: [...] }

Calculation steps

With the default options, the result includes the operations performed by the RPN evaluator:

const output = engine.evaluate("2 + 3");

console.log(output.result.display); // "5"
console.log(output.steps[0]);
// {
//   type: "Operator",
//   name: "+",
//   operands: [...],
//   result: { type: "real", value: 5, display: "5" },
//   stackBefore: [...],
//   stackAfter: [...]
// }

Each step records the operation or function name, consumed operands, result, and stack state before and after the operation.

Normalized results

Normalized values use a discriminated union:

type NormalizedValue =
  | { type: "real"; value: number; display: string }
  | { type: "complex"; re: number; im: number; display: string };

Use display as the recommended presentation value for user interfaces. Use the numeric fields when the consumer needs to perform additional calculations.

Complex results

Operations supported by complex.js, such as the square root of a negative number, can return a normalized complex value:

engine.evaluate("sqrt(-4)", { steps: false });
// { type: "complex", re: 0, im: 2, display: "2i" }

Most trigonometric and logarithmic functions currently evaluate their argument in the real domain. Complex support is therefore operation-dependent rather than a promise that every function accepts complex inputs.

Raw results

Disable normalization to receive numbers or complex.js instances directly:

import Complex from "complex.js";

const value = engine.evaluate("sqrt(-4)", {
  steps: false,
  normalize: false
});

if (value instanceof Complex) {
  console.log(value.re, value.im); // 0 2
}

With steps enabled and normalization disabled, values inside the calculation steps are raw as well.

API reference

polishEngine

The primary consumer API.

const engine = new polishEngine();
engine.evaluate(expression, options?);

EvaluateOptions

interface EvaluateOptions {
  variables?: Record<string, number>;
  steps?: boolean;     // default: true
  normalize?: boolean; // default: true
}

The generated declarations provide overloads for the four steps/normalize return modes. When either flag is a non-literal boolean, TypeScript exposes the complete EvaluateOutput union.

Exported result types

The package exports RawValue, NormalizedValue, Step, NormalizedStep, RawEvaluation, NormalizedEvaluation, EvaluationWithSteps, and EvaluateOutput.

Lower-level exports such as Tokenizer, parser, evaluator, PreprocessModule, ResultNormalizer, and EvaluateOptionsResolver are retained for v2 compatibility. New consumers should prefer the polishEngine facade unless they specifically need an individual pipeline stage.

Supported capabilities

  • Infix-to-postfix conversion with operator precedence and right-associative exponentiation.
  • Arithmetic operators, exponentiation, factorial, and supported comparisons.
  • Parentheses and comma-separated supported functions.
  • Named numeric variables and the constants e and π.
  • Implicit multiplication in supported forms such as 2x and (2 + 3)4.
  • Common functions implemented by the current evaluator, including trigonometric, hyperbolic, logarithmic, root, absolute-value, modulo, percentage, and degree conversions.
  • Normalized real/complex presentation and optional RPN stack traces.

Error behavior

evaluate() returns a value on success and throws an Error on invalid input. It does not encode failures as result objects.

Existing public failures include:

  • Invalid parentheses or Unbalanced parentheses for malformed grouping.
  • Undefined variable: <name> when an expression references a missing variable.
  • Error: insufficient operands when an operator cannot consume enough values.
  • Missing argument for <function> for incomplete function calls.
  • Unknown function: <name> or Unknown operator: <operator> when unsupported tokens reach the evaluator.
  • Error: malformed expression when evaluation does not finish with exactly one stack value.
  • Domain-specific errors such as attempting factorial or comparison with unsupported complex operands.

Messages are useful for diagnostics but are not exported as a formal error-code taxonomy. Consumers should catch Error and avoid depending on exact message text as a stable machine-readable contract.

try {
  engine.evaluate("x + 1", { steps: false });
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message);
  }
}

Architecture

Tokenizer
  ↓
Parser (infix → postfix/RPN)
  ↓
Evaluator
  ↓
Result normalization
  ↓
Optional calculation steps

The facade preprocesses the expression, tokenizes it, converts it to postfix order, evaluates the RPN stack, and finally applies the selected raw/normalized and steps/no-steps output mode. Each stage remains independently testable.

Known limits

  • Polish Engine is not a symbolic CAS.
  • Variables accept real JavaScript numbers.
  • Complex-number behavior varies by operation; most trigonometric and logarithmic functions use real components.
  • The parser accepts the library's documented expression grammar, not arbitrary JavaScript syntax.
  • Angle units are not globally configurable.
  • Error messages are descriptive strings rather than stable error codes.

Development

npm ci
npm run typecheck
npm run build
npm test
npm pack --dry-run

The repository uses npm as its only package manager. CI runs the same validation before changes are merged, and npm publication is triggered only by a deliberate v* Git tag.

Version and releases

Current repository version: 2.0.1 (prepared, not yet published). Current npm release: 2.0.0.

Version 2 introduced option-driven steps and normalization while retaining the legacy variables input. See CHANGELOG.md. Git tags and npm versions are intended to match; release preparation does not publish automatically from ordinary pushes to main.

License

MIT