@tsofist/stem
Advanced tools
+17
-10
@@ -1,14 +0,21 @@ | ||
| import type { PRec, Rec } from '../index'; | ||
| import type { DeepReadonly, PRec, Rec } from '../index'; | ||
| /** | ||
| * Remap object values based on a mapping definition. | ||
| * Remap object values | ||
| */ | ||
| export declare function remap<V extends PRec<unknown>, M extends RemapMap<V>>(map: M | ((formatter: RemapFormatWrapper<V>) => M), values: V): Remap<M, V>; | ||
| export type Remap<M extends RemapMap<V>, V extends PRec<unknown>> = { | ||
| readonly [K in keyof M]: M[K] extends string ? V[M[K]] : M[K] extends RemapFormatWrapperLike<keyof M, infer R> ? R : M[K]; | ||
| export declare function remap<V extends RemapValues, M extends RemapMap<V>>(map: M, values: V): Remap<M, V>; | ||
| /** | ||
| * Remap object values | ||
| */ | ||
| export declare function remap<V extends RemapValues, R>(map: (values: DeepReadonly<V>, format: RemapRootFormatter<V>) => R, values: V): R; | ||
| export type Remap<M extends RemapMap<V>, V extends RemapValues> = { | ||
| readonly [K in keyof M]: M[K] extends string ? V[M[K]] : M[K] extends (...args: unknown[]) => unknown ? M[K] extends RemapFormater<V, infer R> ? R : never : M[K] extends RemapMap<V> ? Remap<M[K], V> : never; | ||
| }; | ||
| type RemapFormatWrapper<V extends PRec<unknown>> = <K extends keyof V, F extends (v: V[K]) => unknown>(key: keyof V, fmt: F) => typeof fmt extends (v: V[typeof key]) => infer R ? RemapFormater<R> : never; | ||
| type RemapFormatWrapperLike<K extends PropertyKey, R> = (key: K, formatter: RemapFormater<R>) => R; | ||
| type RemapFormater<R> = () => R; | ||
| type RemapMapItem<V extends PRec<unknown>> = RemapFormater<V> | object | keyof V; | ||
| type RemapMap<V extends PRec<unknown>> = Rec<RemapMapItem<V>>; | ||
| export type RemapValues = PRec<unknown, string | symbol>; | ||
| export type RemapMap<V extends RemapValues> = Rec<RemapMapItem<V>, RemapMapKey>; | ||
| type RemapMapKey = string | symbol; | ||
| type RemapMapItem<V extends RemapValues> = RemapFormater<V, unknown> | keyof V | { | ||
| [K in RemapMapKey]: RemapMapItem<V>; | ||
| }; | ||
| type RemapFormater<V, R> = (v: DeepReadonly<V>) => R; | ||
| type RemapRootFormatter<V extends RemapValues> = <K extends keyof V, R>(key: K, formatter: (raw: V[K]) => R) => R; | ||
| export {}; |
+22
-24
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.remap = remap; | ||
| /** | ||
| * Remap object values based on a mapping definition. | ||
| */ | ||
| const entries_1 = require("./entries"); | ||
| function remap(map, values) { | ||
| const result = {}; | ||
| if (typeof map === 'function') { | ||
| map = map(createFormatter(values)); | ||
| const formatter = (key, fmt) => { | ||
| const raw = values[key]; | ||
| return fmt(raw); | ||
| }; | ||
| return map(values, formatter); | ||
| } | ||
| for (const [mK, vK] of Object.entries(map)) { | ||
| switch (typeof vK) { | ||
| case 'string': | ||
| result[mK] = values[vK]; | ||
| break; | ||
| case 'function': | ||
| result[mK] = vK(); | ||
| break; | ||
| default: | ||
| result[mK] = vK; | ||
| else { | ||
| const result = {}; | ||
| for (const [key, item] of (0, entries_1.entries)(map)) { | ||
| if (!item) | ||
| continue; | ||
| const itemType = typeof item; | ||
| if (itemType === 'string' || itemType === 'symbol') { | ||
| result[key] = values[item]; | ||
| } | ||
| else if (itemType === 'function') { | ||
| result[key] = item(values); | ||
| } | ||
| else if (itemType === 'object') { | ||
| result[key] = remap(item, values); | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| return result; | ||
| } | ||
| function createFormatter(values) { | ||
| return function format(key, fmt) { | ||
| return () => { | ||
| const raw = values[key]; | ||
| return fmt(raw); | ||
| }; | ||
| }; | ||
| } |
+64
-37
@@ -5,5 +5,6 @@ "use strict"; | ||
| describe('remap', () => { | ||
| it('maps string keys to values', () => { | ||
| const values = { a: 1, b: 'two', c: true }; | ||
| expect((0, remap_1.remap)({ x: 'a', y: 'b', z: 'c' }, values)).toStrictEqual({ | ||
| it('remaps flat object with key map', () => { | ||
| const source = { a: 1, b: 'two', c: true }; | ||
| const result = (0, remap_1.remap)({ x: 'a', y: 'b', z: 'c' }, source); | ||
| expect(result).toEqual({ | ||
| x: 1, | ||
@@ -14,39 +15,65 @@ y: 'two', | ||
| }); | ||
| it('applies formatter functions from a factory', () => { | ||
| const values = { a: 1, b: 'two' }; | ||
| const result = (0, remap_1.remap)((fmt) => ({ | ||
| x: fmt('a', (v) => v + 1), | ||
| y: fmt('b', (v) => v.toUpperCase()), | ||
| }), values); | ||
| expect(result).toStrictEqual({ x: 2, y: 'TWO' }); | ||
| it('remaps flat object with formatter map', () => { | ||
| const source = { a: 2, b: 3 }; | ||
| const result = (0, remap_1.remap)({ | ||
| sum: (vals) => vals.a + vals.b, | ||
| product: (vals) => vals.a * vals.b, | ||
| }, source); | ||
| expect(result).toEqual({ | ||
| sum: 5, | ||
| product: 6, | ||
| }); | ||
| }); | ||
| it('accepts function formater items (constants via function)', () => { | ||
| const values = { a: 1 }; | ||
| const result = (0, remap_1.remap)({ x: () => 5, y: () => 'hello' }, values); | ||
| expect(result).toStrictEqual({ x: 5, y: 'hello' }); | ||
| it('remaps nested object with mixed map', () => { | ||
| const source = { | ||
| a: 10, | ||
| b: 20, | ||
| c: { d: 30, e: 40 }, | ||
| }; | ||
| const result = (0, remap_1.remap)({ | ||
| first: 'a', | ||
| second: (vals) => vals.b * 2, | ||
| nested: { | ||
| third: 'b', | ||
| fourth: (vals) => vals.c.e + 10, | ||
| }, | ||
| }, source); | ||
| expect(result).toStrictEqual({ | ||
| first: 10, | ||
| second: 40, | ||
| nested: { third: 20, fourth: 50 }, | ||
| }); | ||
| }); | ||
| it('returns undefined for missing keys referenced by string', () => { | ||
| const values = { a: 1 }; | ||
| expect((0, remap_1.remap)({ x: 'missing' }, values)).toEqual({ x: undefined }); | ||
| it('remaps using root formatter function', () => { | ||
| const source = { x: 5, y: 15, additional: 100 }; | ||
| const result = (0, remap_1.remap)((values, fmt) => { | ||
| const additional = fmt('additional', (v) => v / 10); | ||
| return { | ||
| total: fmt('x', (v) => v + fmt('y', (w) => w)), | ||
| difference: fmt('y', (v) => v - fmt('x', (w) => w)), | ||
| add: { | ||
| initialX: values.x, | ||
| initialY: values.y, | ||
| additional, | ||
| }, | ||
| pNull: null, | ||
| pNum: 42, | ||
| pBoolF: false, | ||
| pBoolT: true, | ||
| }; | ||
| }, source); | ||
| expect(result).toStrictEqual({ | ||
| total: 20, | ||
| difference: 10, | ||
| add: { | ||
| additional: 10, | ||
| initialX: 5, | ||
| initialY: 15, | ||
| }, | ||
| pNull: null, | ||
| pNum: 42, | ||
| pBoolF: false, | ||
| pBoolT: true, | ||
| }); | ||
| }); | ||
| it('works with class instances as values', () => { | ||
| class MyClass { | ||
| constructor() { | ||
| Object.defineProperty(this, "a", { | ||
| enumerable: true, | ||
| configurable: true, | ||
| writable: true, | ||
| value: 10 | ||
| }); | ||
| Object.defineProperty(this, "b", { | ||
| enumerable: true, | ||
| configurable: true, | ||
| writable: true, | ||
| value: 'ok' | ||
| }); | ||
| } | ||
| } | ||
| const instance = new MyClass(); | ||
| expect((0, remap_1.remap)({ x: 'a', y: 'b' }, instance)).toEqual({ x: 10, y: 'ok' }); | ||
| }); | ||
| }); |
+1
-1
| { | ||
| "name": "@tsofist/stem", | ||
| "version": "5.20.0", | ||
| "version": "5.21.0", | ||
| "description": "Core basics for TypeScript applications", | ||
@@ -5,0 +5,0 @@ "author": "Andrew Berdnikov <tsofistgudmen@gmail.com>", |
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
380462
0.2%9384
0.34%