exprify 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/README.md ADDED
@@ -0,0 +1,34 @@
1
+ ---
2
+ layout: default
3
+ title: Exprify Docs
4
+ ---
5
+
6
+ # Exprify Docs
7
+
8
+ Exprify is a JavaScript expression parser and evaluator for math-heavy apps.
9
+
10
+ ## Highlights
11
+
12
+ - arithmetic, precedence, bigint, and booleans
13
+ - variables, assignments, and inline functions
14
+ - unit conversion
15
+ - matrices and linear algebra helpers
16
+ - complex numbers
17
+ - symbolic helpers like `simplify`, `derivative`, and `rationalize`
18
+
19
+ ## Quick Example
20
+
21
+ ```js
22
+ import Exprify from "exprify";
23
+
24
+ const expr = new Exprify();
25
+
26
+ expr.evaluate("hyp(a, b) = sqrt(a ^ 2 + b ^ 2)");
27
+ console.log(expr.evaluate("hyp(3, 4)"));
28
+ // 5
29
+ ```
30
+
31
+ ## References
32
+
33
+ - [Project README](../README.md)
34
+ - [Token Type Notes](./tokenType.txt)
@@ -0,0 +1,4 @@
1
+ ---
2
+ ---
3
+
4
+ @import "jekyll-theme-primer";
@@ -0,0 +1,21 @@
1
+ Token notes for Exprify
2
+
3
+ - Number
4
+ - BigInt
5
+ - Boolean
6
+ - String
7
+ - Identifier
8
+ - Function
9
+ - Operator
10
+ - UnaryOperator
11
+ - Keyword
12
+ - Unit
13
+ - NumberWithUnit
14
+ - ImaginaryLiteral
15
+ - Parenthesis
16
+ - ArrayStart / ArrayEnd
17
+ - BlockStart / BlockEnd
18
+ - Comma
19
+ - Semicolon
20
+ - Colon
21
+ - Dot
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exprify",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A powerful math expression parser and evaluator with runtime data-type checking",
5
5
  "type": "module",
6
6
  "main": "dist/exprify.cjs.js",
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
@@ -1,40 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- - master
8
- pull_request:
9
- branches:
10
- - main
11
- - master
12
-
13
- jobs:
14
- test:
15
- runs-on: ubuntu-latest
16
-
17
- strategy:
18
- matrix:
19
- node-version:
20
- - 20
21
- - 22
22
-
23
- steps:
24
- - name: Checkout repository
25
- uses: actions/checkout@v4
26
-
27
- - name: Setup Node.js
28
- uses: actions/setup-node@v4
29
- with:
30
- node-version: ${{ matrix.node-version }}
31
- cache: npm
32
-
33
- - name: Install dependencies
34
- run: npm ci
35
-
36
- - name: Build package
37
- run: npm run build
38
-
39
- - name: Run tests
40
- run: npm test
@@ -1,38 +0,0 @@
1
- name: Publish Package
2
-
3
- on:
4
- release:
5
- types:
6
- - published
7
- workflow_dispatch:
8
-
9
- jobs:
10
- publish:
11
- runs-on: ubuntu-latest
12
- permissions:
13
- contents: read
14
-
15
- steps:
16
- - name: Checkout repository
17
- uses: actions/checkout@v4
18
-
19
- - name: Setup Node.js
20
- uses: actions/setup-node@v4
21
- with:
22
- node-version: 22
23
- registry-url: https://registry.npmjs.org/
24
- cache: npm
25
-
26
- - name: Install dependencies
27
- run: npm ci
28
-
29
- - name: Build package
30
- run: npm run build
31
-
32
- - name: Run tests
33
- run: npm test
34
-
35
- - name: Publish to npm
36
- run: npm publish
37
- env:
38
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,34 +0,0 @@
1
- name: Security Audit
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- - master
8
- pull_request:
9
- branches:
10
- - main
11
- - master
12
- schedule:
13
- - cron: "0 6 * * 1"
14
- workflow_dispatch:
15
-
16
- jobs:
17
- audit:
18
- runs-on: ubuntu-latest
19
-
20
- steps:
21
- - name: Checkout repository
22
- uses: actions/checkout@v4
23
-
24
- - name: Setup Node.js
25
- uses: actions/setup-node@v4
26
- with:
27
- node-version: 22
28
- cache: npm
29
-
30
- - name: Install dependencies
31
- run: npm ci
32
-
33
- - name: Run npm audit
34
- run: npm audit --audit-level=high
package/CHANGELOG.md DELETED
@@ -1,11 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on Keep a Changelog, and this project follows semantic versioning.
6
-
7
- ## [1.0.1] - 2026-04-05
8
-
9
- ### Fixed
10
- - Corrected the import path in `src/index.js` to match the actual filename casing of `src/core/Exprify.js`.
11
- - Resolved a cross-platform build issue where Rollup failed on Linux-based CI environments because of case-sensitive path resolution.
package/doc/tokenType.txt DELETED
@@ -1,48 +0,0 @@
1
- ALL TOKEN TYPES (FINAL DESIGN)
2
-
3
- // LITERALS
4
- { type: "Number", value: 10 }
5
- { type: "BigInt", value: 10n }
6
- { type: "Boolean", value: true }
7
- { type: "String", value: "hello" }
8
-
9
- { type: "Unit", value: "cm" }
10
- { type: "NumberWithUnit", value: 12.7, unit: "cm" }
11
- { type: "UnknownUnit", value: 5, unit: "abc" }
12
-
13
- // IDENTIFIERS
14
- { type: "Identifier", value: "x" }
15
-
16
- // FUNCTIONS
17
- { type: "Function", value: "max" }
18
-
19
- // OPERATORS
20
- { type: "Operator", value: "+" }
21
- { type: "Operator", value: ">=" }
22
- { type: "Operator", value: "&&" }
23
- { type: "Operator", value: "|>" }
24
-
25
- // UNARY
26
- { type: "UnaryOperator", value: "-" }
27
- { type: "UnaryOperator", value: "!" }
28
-
29
- // LOGIC / TERNARY
30
- { type: "Ternary", value: "?" }
31
- { type: "Ternary", value: ":" }
32
-
33
- // STRUCTURE
34
- { type: "Parenthesis", value: "(" }
35
- { type: "Parenthesis", value: ")" }
36
- { type: "ArrayStart" }
37
- { type: "ArrayEnd" }
38
- { type: "BlockStart" }
39
- { type: "BlockEnd" }
40
- { type: "Colon" }
41
- { type: "Comma" }
42
- { type: "Dot" }
43
-
44
- // KEYWORDS
45
- { type: "Keyword", value: "to" }
46
- { type: "Keyword", value: "if" }
47
-
48
-
package/rollup.config.js DELETED
@@ -1,80 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
-
4
- import resolve from "@rollup/plugin-node-resolve";
5
- import commonjs from "@rollup/plugin-commonjs";
6
-
7
- import terser from "@rollup/plugin-terser";
8
- import pkg from "./package.json";
9
-
10
- const short_banner = `/*! ${pkg.name} v${pkg.version} | * (c) ${new Date().getFullYear()} ${pkg.author} and contributors | ${pkg.license} License*/`;
11
-
12
- const banner = `/*!
13
- * ${pkg.name} v${pkg.version}
14
- * (c) ${new Date().getFullYear()} ${pkg.author} and other contributors
15
- *
16
- * Released under the ${pkg.license} License
17
- * Date: ${new Date().toISOString().split('T')[0]}
18
- */`;
19
-
20
- function removeComment() {
21
- return {
22
- name: "remove-sourcemap-comment",
23
- writeBundle(outputOptions, bundle) {
24
- for (const fileName in bundle) {
25
- if (fileName.endsWith(".js")) {
26
- const filePath = path.join(
27
- outputOptions.dir || path.dirname(outputOptions.file),
28
- fileName
29
- );
30
-
31
- let code = fs.readFileSync(filePath, "utf-8");
32
-
33
- code = code.replace(/\/\/# sourceMappingURL=.*$/gm, "");
34
-
35
- fs.writeFileSync(filePath, code);
36
- }
37
- }
38
- }
39
- };
40
- }
41
-
42
- export default [
43
- {
44
- input: "src/index.js",
45
- output: [
46
- {
47
- file: "dist/exprify.esm.js",
48
- format: "esm",
49
- sourcemap: true
50
- },
51
- {
52
- file: "dist/exprify.cjs.js",
53
- format: "cjs",
54
- sourcemap: true,
55
- exports: "default"
56
- },
57
- {
58
- file: "dist/exprify.js",
59
- format: "umd",
60
- name: "Exprify",
61
- banner: banner,
62
- sourcemap: true,
63
- indent: true,
64
- exports: "default"
65
- }
66
- ],
67
- plugins: [resolve(), commonjs(), removeComment()]
68
- },
69
- {
70
- input: "src/index.js",
71
- output: {
72
- file: "dist/exprify.min.js",
73
- format: "umd",
74
- name: "Exprify",
75
- sourcemap: true,
76
- banner: short_banner
77
- },
78
- plugins: [resolve(), commonjs(), terser(), removeComment()]
79
- }
80
- ];
Binary file
@@ -1,140 +0,0 @@
1
- import { tokenize } from "../parser/tokenizer.js";
2
- // import { infixToPostfix } from "../parser/infixToPostfix.js";
3
- import { evaluateAST } from "../parser/evaluator.js";
4
- import { createContext } from "./context.js";
5
- import { mathOperations } from "../math/operations.js";
6
-
7
- import { createUnitsStore } from "../utils/store.js";
8
- import { globalUnits } from "../utils/globalUnits.js";
9
-
10
- import { createVarStore } from "../variables/store.js";
11
- import { createFunctionRegistry } from "../function/registry.js";
12
- import { internalFunctions } from "../function/internal.js";
13
-
14
- import { buildAST } from "../parser/astBuild.js";
15
-
16
-
17
- //
18
-
19
- const isComplex = (value) =>
20
- value && typeof value === "object" && "re" in value && "im" in value;
21
-
22
- const isUnitValue = (value) =>
23
- value && typeof value === "object" && "value" in value && "unit" in value;
24
-
25
- const isMatrix = (value) =>
26
- Array.isArray(value) && value.length > 0 && value.every(Array.isArray);
27
-
28
- const formatComplex = (value) => {
29
- if (!isComplex(value)) return value;
30
-
31
- const real = value.re;
32
- const imaginary = Math.abs(value.im);
33
- const sign = value.im < 0 ? "-" : "+";
34
-
35
- if (real === 0) {
36
- if (value.im === 1) return "i";
37
- if (value.im === -1) return "-i";
38
- return `${value.im}i`;
39
- }
40
-
41
- const imagPart = imaginary === 1 ? "i" : `${imaginary}i`;
42
- return `${real} ${sign} ${imagPart}`;
43
- };
44
-
45
- const formatResult = (value) => {
46
- if (isComplex(value)) {
47
- return formatComplex(value);
48
- }
49
-
50
- if (isUnitValue(value)) {
51
- return `${value.value} ${value.unit}`;
52
- }
53
-
54
- if (isMatrix(value)) {
55
- return value.map((row) => row.join("\t")).join("\n");
56
- }
57
-
58
- if (Array.isArray(value)) {
59
- return value.join("\n");
60
- }
61
-
62
- return value;
63
- };
64
-
65
- class exprify {
66
- constructor() {
67
- // Shared state
68
- this.math = mathOperations;
69
- this.units = createUnitsStore(globalUnits);
70
- this.functions = createFunctionRegistry(internalFunctions);
71
- this.variables = createVarStore();
72
- this._cache = new Map();
73
- }
74
-
75
- setVariable(name, value) {
76
- this.variables.set(name, value);
77
- }
78
-
79
- getVariable(name) {
80
- return this.variables.get(name);
81
- }
82
-
83
- addFunction(name, fn) {
84
- this.functions.register(name, fn);
85
- }
86
-
87
- _createContext() {
88
- return createContext({
89
- functions: this.functions,
90
- variables: this.variables,
91
- units: this.units,
92
- evaluate: this.evaluate.bind(this)
93
- });
94
- }
95
-
96
- tokenize(expr) {
97
- if (typeof expr !== "string") {
98
- throw new Error("Expression must be a string");
99
- }
100
- return tokenize(expr, this._createContext());
101
- }
102
-
103
- parse(expr) {
104
- const tokens = this.tokenize(expr);
105
- const ast = buildAST(tokens);
106
- return { tokens, ast };
107
- }
108
-
109
- evaluate(expr) {
110
- const { ast } = this.parse(expr);
111
- return formatResult(evaluateAST(
112
- ast,
113
- this._createContext()
114
- ));
115
- }
116
-
117
- compile(expr) {
118
- if (this._cache.has(expr)) {
119
- return this._cache.get(expr);
120
- }
121
-
122
- const { ast } = this.parse(expr);
123
-
124
- const compiledFn = (scope = {}) => {
125
- const baseContext = this._createContext();
126
- const scopedContext = baseContext.withScope(scope);
127
- return formatResult(evaluateAST(ast, scopedContext));
128
- };
129
-
130
- this._cache.set(expr, compiledFn);
131
- return compiledFn;
132
- }
133
-
134
- clearCache() {
135
- this._cache.clear();
136
- }
137
-
138
- }
139
-
140
- export default exprify;
@@ -1,30 +0,0 @@
1
- export function createContext({ variables, functions, units, evaluate}) {
2
- if (!variables) throw new Error("Variable store missing");
3
- if (!functions) throw new Error("Function registry missing");
4
- if (!units) throw new Error("Units list missing");
5
- if (!evaluate) throw new Error("evaluate function missing");
6
-
7
- return {
8
- variables: variables,
9
- functions: functions,
10
- units: units,
11
- evaluate,
12
- withScope(scope = {}) {
13
- const tempVars = {
14
- ...variables.all?.(),
15
- ...scope
16
- };
17
- return createContext({
18
- functions: functions,
19
- evaluate,
20
- units,
21
- variables: {
22
- get: (k) => tempVars[k],
23
- set: (k, v) => (tempVars[k] = v),
24
- all: () => tempVars
25
- }
26
- });
27
-
28
- }
29
- };
30
- }
@@ -1,64 +0,0 @@
1
- export function createFunctionExecutor(fnRegistry, options = {}) {
2
- if (!fnRegistry) {
3
- throw new Error("Function registry is required");
4
- }
5
-
6
- const config = {
7
- strict: options.strict ?? true
8
- };
9
-
10
- /* ================= EXECUTE ================= */
11
-
12
- function execute(name, args = [], context) {
13
- const fn = fnRegistry.get(name);
14
-
15
- /* ----- NOT FOUND ----- */
16
- if (!fn) {
17
- if (config.strict) {
18
- throw new Error(`Unknown function: ${name}`);
19
- }
20
- return undefined;
21
- }
22
-
23
- /* ----- VALIDATE ARGS ----- */
24
- if (!Array.isArray(args)) {
25
- throw new Error(`Arguments for "${name}" must be an array`);
26
- }
27
-
28
- /* ----- EXECUTE ----- */
29
- try {
30
- return fn(...args);
31
- } catch (err) {
32
- throw new Error(
33
- `Error in function "${name}": ${err.message}`
34
- );
35
- }
36
- }
37
-
38
- /* ================= SAFE EXECUTE ================= */
39
-
40
- function safeExecute(name, args = [], context) {
41
- try {
42
- return execute(name, args, context);
43
- } catch (err) {
44
- return {
45
- error: true,
46
- message: err.message
47
- };
48
- }
49
- }
50
-
51
- /* ================= EXISTS ================= */
52
-
53
- function exists(name) {
54
- return fnRegistry.has(name);
55
- }
56
-
57
- /* ================= API ================= */
58
-
59
- return {
60
- execute,
61
- safeExecute,
62
- exists
63
- };
64
- }