npm package: @songjin-ai/sttool
Description: TypeScript utility library with high-precision calculation and date formatting
Author: songjin
Latest version: 1.0.1

# sttool

TypeScript utility library with high-precision calculation, date formatting, and tree structure conversion.

## Install

```bash
npm install @songjin-ai/sttool
```

## Modules

- [Decimal](#decimal) — High-precision decimal arithmetic
- [DateTime](#datetime) — Chainable date manipulation
- [Tree](#tree) — List ↔ Tree structure conversion
- [Object](#object) — Object property and structure utilities

---

## Decimal

High-precision decimal arithmetic using string-based calculation. Solves IEEE 754 floating-point precision issues like `0.1 + 0.2 !== 0.3`.

### Import

```ts
import { Decimal } from '@songjin-ai/sttool';
```

### Static Methods

| Method | Description |
|--------|-------------|
| `Decimal.add(a, b)` | Add two numbers |
| `Decimal.subtract(a, b)` | Subtract b from a |
| `Decimal.multiply(a, b)` | Multiply two numbers |
| `Decimal.divide(a, b, precision?)` | Divide a by b (default precision: 20) |
| `Decimal.mod(a, b)` | Modulo operation |

### Instance Methods

| Method | Description |
|--------|-------------|
| `.add(other)` | Add to current value |
| `.subtract(other)` | Subtract from current value |
| `.multiply(other)` | Multiply by other value |
| `.divide(other, precision?)` | Divide by other value |
| `.mod(other)` | Modulo operation |
| `.negate()` | Negate the value |
| `.abs()` | Absolute value |
| `.equals(other)` | Check equality |
| `.compareTo(other)` | Compare (-1, 0, 1) |
| `.toNumber()` | Convert to JavaScript number |
| `.toString()` | Convert to string |
| `.toFixed(decimals)` | Format with fixed decimals |

### Examples

```ts
// Precision arithmetic
const a = Decimal.add('0.1', '0.2');
const b = Decimal.from('0.3');
a.equals(b); // true (unlike JavaScript: 0.1 + 0.2 !== 0.3)

// Chaining
const result = Decimal.from('10')
  .subtract('3.5')
  .multiply('2')
  .divide('5');

// Fixed precision for display
Decimal.divide('1', '3', 4).toString(); // '0.3333'
Decimal.divide('1', '3').toFixed(4);    // '0.3333'

// Financial calculations
const price = Decimal.from('19.99');
const tax = Decimal.multiply(price, '0.08');
const total = price.add(tax);
total.toString(); // '21.5892'
```

---

## DateTime

Chainable date manipulation with fluent API and template-based formatting.

### Import

```ts
import { DateTime, format, parseDate, isValidDate } from '@songjin-ai/sttool';
```

### Creating DateTime

| Method | Description |
|--------|-------------|
| `DateTime.now()` | Current date/time |
| `DateTime.from(value)` | From string, Date, or DateTime |
| `DateTime.create(year, month, day, hour?, minute?, second?)` | From components |

### Chainable Methods

| Method | Description |
|--------|-------------|
| `.add(value, unit)` | Add to unit |
| `.subtract(value, unit)` | Subtract from unit |
| `.set(unit, value)` | Set unit to value |
| `.startOf(unit)` | Set to start of unit |
| `.endOf(unit)` | Set to end of unit |
| `.get(unit)` | Get unit value |

### Comparison Methods

| Method | Description |
|--------|-------------|
| `.isBefore(other)` | Check if before |
| `.isAfter(other)` | Check if after |
| `.isSame(other)` | Check if same |
| `.compareTo(other)` | Compare (-1, 0, 1) |
| `.diffDays(other)` | Difference in days |

### Output Methods

| Method | Description |
|--------|-------------|
| `.format(template)` | Format with template |
| `.toDate()` | Get native Date |
| `.toMillis()` | Get timestamp (ms) |
| `.toSeconds()` | Get timestamp (s) |

### Format Tokens

| Token | Output | Example |
|-------|--------|---------|
| `YYYY` | 4-digit year | 2026 |
| `YY` | 2-digit year | 26 |
| `MMMM` | Full month name | January |
| `MMM` | Short month name | Jan |
| `MM` | 2-digit month | 01 |
| `M` | Month number | 1 |
| `DD` | 2-digit day | 05 |
| `D` | Day number | 5 |
| `HH` | 2-digit hour (24h) | 14 |
| `H` | Hour (24h) | 14 |
| `mm` | 2-digit minute | 30 |
| `m` | Minute | 30 |
| `ss` | 2-digit second | 05 |
| `s` | Second | 5 |

### Examples

```ts
// Chainable manipulation
DateTime.now()
  .add(1, 'month')
  .startOf('day')
  .format('YYYY-MM-DD'); // '2026-05-01'

// Date comparison
const a = DateTime.from('2026-01-15');
const b = DateTime.from('2026-02-20');
a.isBefore(b);     // true
a.diffDays(b);     // 36

// Formatting
DateTime.now().format('YYYY-MM-DD HH:mm:ss');
// '2026-04-03 14:30:00'

// Parse and validate
parseDate('2026-04-03');     // returns Date
isValidDate('invalid');      // false
```

---

## Tree

Convert between flat lists and nested tree structures.

### Import

```ts
import { listToTree, treeToList, TreeNode } from '@songjin-ai/sttool';
```

### Types

```ts
interface TreeNode<T = unknown> {
  id: string | number;
  parentId: string | number | null;
  children?: T[];
  [key: string]: unknown;
}
```

### listToTree

Convert a flat list with `parentId` references into a nested tree structure.

```ts
const list = [
  { id: 1, parentId: null, name: 'Root' },
  { id: 2, parentId: 1, name: 'Child 1' },
  { id: 3, parentId: 1, name: 'Child 2' },
  { id: 4, parentId: 2, name: 'Grandchild' },
];

const tree = listToTree(list);
// Result:
// [
//   {
//     id: 1, parentId: null, name: 'Root', children: [
//       { id: 2, parentId: 1, name: 'Child 1', children: [
//         { id: 4, parentId: 2, name: 'Grandchild', children: [] }
//       ]},
//       { id: 3, parentId: 1, name: 'Child 2', children: [] }
//     ]
//   }
// ]
```

### treeToList

Convert a nested tree structure back to a flat list.

```ts
const flat = treeToList(tree);
// [
//   { id: 1, parentId: null, name: 'Root' },
//   { id: 2, parentId: 1, name: 'Child 1' },
//   { id: 3, parentId: 1, name: 'Child 2' },
//   { id: 4, parentId: 2, name: 'Grandchild' }
// ]

// With depth information
const withDepth = treeToList(tree, { includeDepth: true });
// [
//   { id: 1, parentId: null, name: 'Root', depth: 0 },
//   { id: 2, parentId: 1, name: 'Child 1', depth: 1 },
//   ...
// ]
```

### Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `includeDepth` | `boolean` | `false` | Include depth level in output |
| `childrenKey` | `string` | `'children'` | Key name for children array |

### Use Cases

- **Organizational structures** — Convert database records to tree for UI
- **File systems** — Convert flat file list to nested directories
- **Menus/Navigation** — Build nested menu from flat menu items
- **Category trees** — E-commerce product categories

---

## Object

Object property and structure manipulation utilities.

### Import

```ts
import { deepGet, deepMerge, pick, omit, flatten, unflatten, orderBy, sortBy } from '@songjin-ai/sttool';
```

### deepGet

Safely get nested values with dot notation path and default fallback.

```ts
deepGet({ a: { b: { c: 1 } } }, 'a.b.c');           // 1
deepGet({ a: { b: [1, 2, 3] } }, 'a.b.1');          // 2
deepGet({ a: {} }, 'a.b.c', 'default');             // 'default'
deepGet(null, 'a.b.c', 'default');                  // 'default'
```

### deepMerge

Deep merge two objects. Arrays are replaced, not concatenated.

```ts
deepMerge({ a: { b: 1 } }, { a: { c: 2 } });  // { a: { b: 1, c: 2 } }
deepMerge({ a: [1, 2] }, { a: [3] });          // { a: [3] }
deepMerge({ a: 1 }, null);                      // { a: 1 }
```

### pick / omit

Select or exclude object properties.

```ts
const obj = { a: 1, b: 2, c: 3 };

pick(obj, ['a', 'c']);       // { a: 1, c: 3 }
pick(obj, 'a');               // { a: 1 } (string overload)

omit(obj, ['a', 'c']);       // { b: 2 }
omit(obj, 'a');               // { b: 2, c: 3 } (string overload)
```

### flatten / unflatten

Convert between nested and flat object structures with custom delimiter support.

```ts
// Flatten nested object
flatten({ a: { b: { c: 1 }, d: 2 } });
// { 'a.b.c': 1, 'a.d': 2 }

// Custom delimiter
flatten({ a: { b: 1 } }, { delimiter: '-' });
// { 'a-b': 1 }

// Unflatten back to nested
unflatten({ 'a.b.c': 1, 'a.d': 2 });
// { a: { b: { c: 1 }, d: 2 } }

// Arrays are preserved
flatten({ a: [1, 2, { b: 3 }] });
// { 'a.0': 1, 'a.1': 2, 'a.2.b': 3 }
```

### orderBy / sortBy

Multi-key sorting for object arrays. Stable sort — preserves original order for equal keys.

```ts
// Sort by score descending, then chinese ascending
orderBy(users, ['score', 'chinese'], ['desc', 'asc']);

// Single key sort
sortBy(users, 'score', 'desc');

// Default ascending
sortBy(users, 'name');
```

---

## License

MIT