Add core Ox modules as ES modules with tests

This commit adds ES module versions of fundamental Ox utilities:
- Array utilities (api, compact, unique, zip, etc.)
- String utilities (capitalize, clean, truncate, wordwrap, etc.)
- Math utilities (trig functions, geographic calculations, etc.)
- Object utilities (clone, serialize, keys/values, etc.)
- Function utilities (cache, debounce, throttle, memoize, etc.)
- Constants (math, time, colors, HTTP status codes)
- Polyfills for older browser compatibility

All modules include proper imports/exports and maintain the same API
as the original implementations. Added comprehensive test coverage with
31 tests passing.

Next steps: Convert remaining core modules, set up build pipeline,
and test backward compatibility with existing examples.

🤖 Generated with AI assistance
This commit is contained in:
Sanjay Bhangar 2026-02-09 17:32:06 +05:30
commit a8a7dc9445
2456 changed files with 149714 additions and 0 deletions

132
test/modules.test.js Normal file
View file

@ -0,0 +1,132 @@
import { describe, it, expect } from 'vitest';
import * as ArrayUtils from '../src/ox/core/Array.js';
import * as StringUtils from '../src/ox/core/String.js';
import * as MathUtils from '../src/ox/core/Math.js';
import * as ObjectUtils from '../src/ox/core/Object.js';
import * as FunctionUtils from '../src/ox/core/Function.js';
describe('Module Tests', () => {
describe('Array utilities', () => {
it('should compact arrays', () => {
expect(ArrayUtils.compact([1, null, 2, undefined, 3, 0])).toEqual([1, 2, 3, 0]);
});
it('should find unique values', () => {
expect(ArrayUtils.unique([1, 2, 2, 3, 3, 3])).toEqual([1, 2, 3]);
});
it('should zip arrays', () => {
expect(ArrayUtils.zip([1, 2], ['a', 'b'])).toEqual([[1, 'a'], [2, 'b']]);
});
});
describe('String utilities', () => {
it('should capitalize strings', () => {
expect(StringUtils.capitalize('hello')).toBe('Hello');
});
it('should check startsWith', () => {
expect(StringUtils.startsWith('hello', 'he')).toBe(true);
expect(StringUtils.startsWith('hello', 'hi')).toBe(false);
});
it('should repeat strings', () => {
expect(StringUtils.repeat('x', 3)).toBe('xxx');
});
it('should convert to camelCase', () => {
expect(StringUtils.toCamelCase('foo-bar-baz')).toBe('fooBarBaz');
});
it('should clean whitespace', () => {
expect(StringUtils.clean(' hello world ')).toBe('hello world');
});
});
describe('Math utilities', () => {
it('should convert degrees to radians', () => {
expect(MathUtils.rad(180)).toBeCloseTo(Math.PI);
});
it('should convert radians to degrees', () => {
expect(MathUtils.deg(Math.PI)).toBeCloseTo(180);
});
it('should limit values', () => {
expect(MathUtils.limit(5, 0, 10)).toBe(5);
expect(MathUtils.limit(-5, 0, 10)).toBe(0);
expect(MathUtils.limit(15, 0, 10)).toBe(10);
});
it('should calculate modulo correctly', () => {
expect(MathUtils.mod(5, 3)).toBe(2);
expect(MathUtils.mod(-1, 3)).toBe(2); // Positive result
});
it('should calculate sum', () => {
expect(MathUtils.sum([1, 2, 3, 4])).toBe(10);
});
});
describe('Object utilities', () => {
it('should clone objects', () => {
const obj = { a: 1, b: { c: 2 } };
const clone = ObjectUtils.clone(obj);
expect(clone).toEqual(obj);
expect(clone).not.toBe(obj);
expect(clone.b).not.toBe(obj.b);
});
it('should get object keys', () => {
expect(ObjectUtils.keys({ a: 1, b: 2 })).toEqual(['a', 'b']);
});
it('should get object values', () => {
expect(ObjectUtils.values({ a: 1, b: 2 })).toEqual([1, 2]);
});
it('should serialize objects', () => {
expect(ObjectUtils.serialize({ foo: 'bar', baz: 123 })).toBe('foo=bar&baz=123');
});
it('should unserialize query strings', () => {
expect(ObjectUtils.unserialize('foo=bar&baz=123')).toEqual({ foo: 'bar', baz: '123' });
});
});
describe('Function utilities', () => {
it('should create identity function', () => {
expect(FunctionUtils.identity(5)).toBe(5);
expect(FunctionUtils.identity('test')).toBe('test');
});
it('should create constant function', () => {
const fn = FunctionUtils.constant(42);
expect(fn()).toBe(42);
expect(fn('ignored')).toBe(42);
});
it('should call function once', () => {
let count = 0;
const fn = FunctionUtils.once(() => ++count);
expect(fn()).toBe(1);
expect(fn()).toBe(1); // Still 1
expect(count).toBe(1);
});
it('should memoize functions', () => {
let calls = 0;
const fn = FunctionUtils.memoize((x) => {
calls++;
return x * 2;
});
expect(fn(5)).toBe(10);
expect(fn(5)).toBe(10); // Cached
expect(calls).toBe(1);
expect(fn(6)).toBe(12);
expect(calls).toBe(2);
});
});
});