yummies 7.12.0 → 7.13.0

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.
Files changed (122) hide show
  1. package/README.md +5 -87
  2. package/async.cjs +17 -0
  3. package/async.cjs.map +1 -1
  4. package/async.d.ts +17 -0
  5. package/async.js +17 -0
  6. package/async.js.map +1 -1
  7. package/common.cjs.map +1 -1
  8. package/common.d.ts +18 -0
  9. package/common.js.map +1 -1
  10. package/complex.cjs.map +1 -1
  11. package/complex.d.ts +66 -0
  12. package/complex.js.map +1 -1
  13. package/cookie.cjs.map +1 -1
  14. package/cookie.d.ts +18 -0
  15. package/cookie.js.map +1 -1
  16. package/css.cjs +16 -0
  17. package/css.cjs.map +1 -1
  18. package/css.d.ts +17 -0
  19. package/css.js +16 -0
  20. package/css.js.map +1 -1
  21. package/data.cjs.map +1 -1
  22. package/data.d.ts +18 -0
  23. package/data.js.map +1 -1
  24. package/date-time.cjs +16 -0
  25. package/date-time.cjs.map +1 -1
  26. package/date-time.d.ts +17 -0
  27. package/date-time.js +16 -0
  28. package/date-time.js.map +1 -1
  29. package/device.cjs +17 -0
  30. package/device.cjs.map +1 -1
  31. package/device.d.ts +17 -0
  32. package/device.js +17 -0
  33. package/device.js.map +1 -1
  34. package/encodings.cjs.map +1 -1
  35. package/encodings.d.ts +17 -0
  36. package/encodings.js.map +1 -1
  37. package/errors.cjs +16 -0
  38. package/errors.cjs.map +1 -1
  39. package/errors.d.ts +17 -0
  40. package/errors.js +16 -0
  41. package/errors.js.map +1 -1
  42. package/file.cjs +16 -0
  43. package/file.cjs.map +1 -1
  44. package/file.d.ts +16 -0
  45. package/file.js +16 -0
  46. package/file.js.map +1 -1
  47. package/format.cjs.map +1 -1
  48. package/format.d.ts +18 -0
  49. package/format.js.map +1 -1
  50. package/html.cjs +16 -0
  51. package/html.cjs.map +1 -1
  52. package/html.d.ts +17 -0
  53. package/html.js +16 -0
  54. package/html.js.map +1 -1
  55. package/id.cjs +16 -0
  56. package/id.cjs.map +1 -1
  57. package/id.d.ts +16 -0
  58. package/id.js +16 -0
  59. package/id.js.map +1 -1
  60. package/imports.cjs +16 -0
  61. package/imports.cjs.map +1 -1
  62. package/imports.d.ts +16 -0
  63. package/imports.js +16 -0
  64. package/imports.js.map +1 -1
  65. package/math.cjs.map +1 -1
  66. package/math.d.ts +17 -0
  67. package/math.js.map +1 -1
  68. package/media.cjs +16 -0
  69. package/media.cjs.map +1 -1
  70. package/media.d.ts +16 -0
  71. package/media.js +16 -0
  72. package/media.js.map +1 -1
  73. package/mobx.cjs +96 -0
  74. package/mobx.cjs.map +1 -1
  75. package/mobx.d.ts +101 -0
  76. package/mobx.js +96 -0
  77. package/mobx.js.map +1 -1
  78. package/ms.cjs +16 -0
  79. package/ms.cjs.map +1 -1
  80. package/ms.d.ts +16 -0
  81. package/ms.js +16 -0
  82. package/ms.js.map +1 -1
  83. package/number.cjs +16 -0
  84. package/number.cjs.map +1 -1
  85. package/number.d.ts +16 -0
  86. package/number.js +16 -0
  87. package/number.js.map +1 -1
  88. package/package.json +2 -2
  89. package/parser.cjs.map +1 -1
  90. package/parser.d.ts +17 -0
  91. package/parser.js.map +1 -1
  92. package/price.cjs.map +1 -1
  93. package/price.d.ts +16 -0
  94. package/price.js.map +1 -1
  95. package/random.cjs +16 -0
  96. package/random.cjs.map +1 -1
  97. package/random.d.ts +16 -0
  98. package/random.js +16 -0
  99. package/random.js.map +1 -1
  100. package/sound.cjs +16 -0
  101. package/sound.cjs.map +1 -1
  102. package/sound.d.ts +16 -0
  103. package/sound.js +16 -0
  104. package/sound.js.map +1 -1
  105. package/storage.cjs.map +1 -1
  106. package/storage.d.ts +16 -0
  107. package/storage.js.map +1 -1
  108. package/text.cjs +16 -0
  109. package/text.cjs.map +1 -1
  110. package/text.d.ts +16 -0
  111. package/text.js +16 -0
  112. package/text.js.map +1 -1
  113. package/type-guard.cjs.map +1 -1
  114. package/type-guard.d.ts +18 -0
  115. package/type-guard.js.map +1 -1
  116. package/types.d.ts +41 -0
  117. package/types.global.d.ts +41 -0
  118. package/vibrate.cjs +16 -0
  119. package/vibrate.cjs.map +1 -1
  120. package/vibrate.d.ts +16 -0
  121. package/vibrate.js +16 -0
  122. package/vibrate.js.map +1 -1
package/mobx.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mobx.js","names":[],"sources":["../src/mobx/apply-observable.ts","../src/mobx/create-enhanced-atom.ts","../src/mobx/create-ref.ts","../src/mobx/deep-observable-struct.ts","../src/mobx/get-mobx-administration.ts","../src/mobx/lazy-observe.ts"],"sourcesContent":["import { type AnnotationMapEntry, makeObservable } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\nexport type ObservableAnnotationsArray<T extends AnyObject = AnyObject> = [\n AnnotationMapEntry,\n ...(keyof T | (string & {}))[],\n][];\n\n/**\n * Applies a compact list of MobX annotations to an object using either\n * decorator-style invocation or the annotation map form accepted by `makeObservable`.\n *\n * @template T Target object type.\n * @param context Object that should become observable.\n * @param annotationsArray Tuples of annotation followed by annotated field names.\n * @param useDecorators Enables decorator-style application before calling `makeObservable`.\n *\n * @example\n * ```ts\n * applyObservable(store, [[observable, 'items'], [action, 'setItems']]);\n * ```\n *\n * @example\n * ```ts\n * applyObservable(viewModel, [[computed, 'fullName']], true);\n * ```\n */\nexport const applyObservable = <T extends AnyObject>(\n context: T,\n annotationsArray: ObservableAnnotationsArray<T>,\n useDecorators?: boolean,\n) => {\n if (useDecorators) {\n annotationsArray.forEach(([annotation, ...fields]) => {\n fields.forEach((field) => {\n // @ts-expect-error\n annotation(context, field);\n });\n });\n\n makeObservable(context);\n } else {\n const annotationsObject: AnyObject = {};\n\n annotationsArray.forEach(([annotation, ...fields]) => {\n fields.forEach((field) => {\n annotationsObject[field] = annotation;\n });\n });\n\n makeObservable(context, annotationsObject);\n }\n};\n","import { createAtom, type IAtom } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\nexport interface IEnhancedAtom<TMeta extends AnyObject = AnyObject>\n extends IAtom {\n meta: TMeta;\n}\n\n/**\n * Creates a MobX atom extended with metadata and bound reporting methods.\n *\n * @template TMeta Metadata object stored on the atom.\n * @param name Atom name used by MobX for debugging.\n * @param onBecomeObservedHandler Callback fired when the atom becomes observed.\n * @param onBecomeUnobservedHandler Callback fired when the atom is no longer observed.\n * @param meta Optional metadata attached to the atom.\n * @returns Atom instance with `meta`, `reportChanged` and `reportObserved`.\n *\n * @example\n * ```ts\n * const atom = createEnhancedAtom('user-status');\n * atom.reportChanged();\n * ```\n *\n * @example\n * ```ts\n * const atom = createEnhancedAtom('cache', undefined, undefined, { scope: 'users' });\n * atom.meta.scope;\n * ```\n */\nexport const createEnhancedAtom = <TMeta extends AnyObject>(\n name: string,\n onBecomeObservedHandler?: (atom: IEnhancedAtom<TMeta>) => void,\n onBecomeUnobservedHandler?: (atom: IEnhancedAtom<TMeta>) => void,\n meta?: TMeta,\n): IEnhancedAtom<TMeta> => {\n const atom = createAtom(\n name,\n onBecomeObservedHandler && (() => onBecomeObservedHandler(atom)),\n onBecomeUnobservedHandler && (() => onBecomeUnobservedHandler(atom)),\n ) as IEnhancedAtom<TMeta>;\n atom.meta = meta ?? ({} as TMeta);\n atom.reportChanged = atom.reportChanged.bind(atom);\n atom.reportObserved = atom.reportObserved.bind(atom);\n return atom;\n};\n","import {\n type IEqualsComparer,\n makeObservable,\n comparer as mobxComparer,\n observable,\n runInAction,\n} from 'mobx';\nimport type { AnyObject, Maybe } from 'yummies/types';\n\n/**\n * You can return `false` if you don't want to change the value in this ref\n */\nexport type RefChangeListener<T> = (\n value: T | null,\n prevValue: T | undefined,\n) => void | false;\n\n/**\n * Alternative to React.createRef but works in MobX world.\n * Typically it the should be the same React.LegacyRef (fn style)\n */\nexport interface Ref<T = any, TMeta = AnyObject> {\n /**\n * Setter function\n */\n (value: Maybe<T>): void;\n\n set(value: Maybe<T>): void;\n listeners: Set<RefChangeListener<NoInfer<T>>>;\n current: NoInfer<T> | null;\n meta: TMeta;\n}\n\nexport interface CreateRefConfig<T = any, TMeta = AnyObject> {\n onSet?: (node: T, prevValue: T | undefined) => void;\n onUnset?: (lastValue: T | undefined) => void;\n onChange?: RefChangeListener<T>;\n meta?: TMeta;\n initial?: Maybe<T>;\n comparer?: IEqualsComparer<T | null>;\n}\n\n/**\n * Creates a MobX-aware ref that behaves like a callback ref and exposes\n * observable `current` and `meta` fields.\n *\n * @template T Referenced value type.\n * @template TMeta Additional observable metadata stored on the ref.\n * @param cfg Optional callbacks, initial value and comparer configuration.\n * @returns Observable ref function object.\n *\n * @example\n * ```ts\n * const inputRef = createRef<HTMLInputElement>();\n * inputRef.set(document.createElement('input'));\n * ```\n *\n * @example\n * ```ts\n * const ref = createRef<number>();\n * ref(3);\n * ref.current; // 3\n * ```\n *\n * @example\n * ```ts\n * const nodeRef = createRef({\n * onUnset: () => console.log('detached'),\n * meta: { mounted: false },\n * });\n * ```\n */\nexport const createRef = <T = any, TMeta = AnyObject>(\n cfg?: CreateRefConfig<T, TMeta>,\n): Ref<T, TMeta> => {\n let lastValue: T | undefined;\n const comparer = cfg?.comparer ?? mobxComparer.default;\n\n const setValue: Ref<T, TMeta>['set'] = (value) => {\n const nextValue = value ?? null;\n\n if (comparer(ref.current, nextValue)) {\n return;\n }\n\n runInAction(() => {\n const prevLastValue = lastValue;\n lastValue = ref.current ?? undefined;\n ref.current = nextValue;\n\n let isNextValueIgnored = false;\n\n ref.listeners.forEach((listener) => {\n const listenerResult = listener(ref.current, lastValue);\n\n if (listenerResult === false) {\n isNextValueIgnored = true;\n }\n });\n\n if (isNextValueIgnored) {\n lastValue = prevLastValue;\n ref.current = lastValue ?? null;\n } else if (ref.current === null && lastValue !== undefined) {\n lastValue = undefined;\n }\n });\n };\n\n const ref = setValue as Ref<T, TMeta>;\n\n ref.set = setValue;\n\n ref.listeners = new Set(cfg?.onChange ? [cfg.onChange] : []);\n\n if (cfg?.onSet || cfg?.onUnset) {\n ref.listeners.add((value, prevValue) => {\n if (value) {\n cfg.onSet?.(value, prevValue);\n } else {\n cfg.onUnset?.(prevValue);\n }\n });\n }\n\n ref.current = cfg?.initial ?? null;\n ref.meta = cfg?.meta ?? ({} as TMeta);\n\n makeObservable(ref, {\n current: observable.ref,\n meta: observable,\n });\n\n return ref;\n};\n\n/**\n * Checks whether the provided value is a ref created by `createRef`.\n *\n * @template T Referenced value type.\n * @template TMeta Ref metadata type.\n * @param value Value to inspect.\n * @returns `true` when the value is a ref-like function with `current`.\n *\n * @example\n * ```ts\n * const ref = createRef<number>();\n * isRef(ref); // true\n * ```\n *\n * @example\n * ```ts\n * isRef({ current: 1 }); // false\n * ```\n */\nexport const isRef = <T, TMeta = any>(\n value: T | Ref<T, TMeta>,\n): value is Ref<T, TMeta> => {\n return typeof value === 'function' && 'current' in value;\n};\n\n/**\n * Normalizes a plain value or an existing ref into a `Ref` instance.\n *\n * @template T Referenced value type.\n * @template TMeta Ref metadata type.\n * @param value Existing ref or initial plain value.\n * @param cfg Optional ref configuration applied when a new ref is created.\n * @returns Existing ref or a newly created ref initialized with `value`.\n *\n * @example\n * ```ts\n * const ref = toRef(document.body);\n * ref.current === document.body;\n * ```\n *\n * @example\n * ```ts\n * const existingRef = createRef<number>();\n * const sameRef = toRef(existingRef);\n * ```\n */\nexport const toRef = <T, TMeta = any>(\n value: T | Ref<T, TMeta>,\n cfg?: Omit<CreateRefConfig<T, TMeta>, 'initial'>,\n): Ref<T, TMeta> => {\n return isRef(value) ? value : createRef({ initial: value, ...cfg });\n};\n","import { action, makeObservable, observable } from 'mobx';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { AnyObject } from 'yummies/types';\n\n/**\n * Wraps a plain object into a deeply observable structure and allows\n * patch-like updates while preserving nested observable references where possible.\n *\n * @template TData Observable object shape.\n *\n * @example\n * ```ts\n * const state = new DeepObservableStruct({ user: { name: 'Ann' } });\n * state.set({ user: { name: 'Bob' } });\n * ```\n *\n * @example\n * ```ts\n * const state = new DeepObservableStruct({ filters: { active: true } });\n * state.set({ filters: { active: false, archived: true } });\n * ```\n */\nexport class DeepObservableStruct<TData extends AnyObject> {\n data: TData;\n\n constructor(data: TData) {\n this.data = data;\n\n makeObservable(this, {\n data: observable.deep,\n set: action,\n });\n }\n\n set(newData: Partial<TData>) {\n type StackItem = [key: string, currObservable: AnyObject, new: AnyObject];\n\n const stack: StackItem[] = Object.keys(this.data).map((key) => [\n key,\n this.data,\n newData,\n ]);\n\n let currentIndex = 0;\n let stackLength = stack.length;\n\n while (currentIndex < stackLength) {\n const [key, currObservableData, newData] = stack[currentIndex];\n const newValue = newData[key];\n const currValue = currObservableData[key];\n\n currentIndex++;\n\n if (key in newData) {\n if (typeGuard.isObject(newValue) && typeGuard.isObject(currValue)) {\n const newValueKeys = Object.keys(newValue);\n\n Object.keys(currValue).forEach((childKey) => {\n if (!(childKey in newValue)) {\n delete currObservableData[key][childKey];\n }\n });\n\n newValueKeys.forEach((childKey) => {\n const length = stack.push([\n childKey,\n currObservableData[key],\n newValue,\n ]);\n stackLength = length;\n });\n } else if (newValue !== currValue) {\n currObservableData[key] = newValue;\n }\n } else {\n delete currObservableData[key];\n }\n }\n\n Object.keys(newData).forEach((newDataKey) => {\n if (!this.data[newDataKey]) {\n // @ts-expect-error\n this.data[newDataKey] = newData[newDataKey];\n }\n });\n }\n}\n","import { $mobx, type AnnotationMapEntry } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\ntype ObservableObjectAdministration = Parameters<\n Exclude<AnnotationMapEntry, boolean>['make_']\n>[0];\n\n/**\n * Returns the internal MobX administration object associated with an observable target.\n *\n * @param context Observable object instance.\n * @returns MobX administration internals stored under `$mobx`.\n *\n * @example\n * ```ts\n * const admin = getMobxAdministration(store);\n * admin.name_;\n * ```\n *\n * @example\n * ```ts\n * const values = getMobxAdministration(formState).values_;\n * ```\n */\nexport const getMobxAdministration = (\n context: AnyObject,\n): ObservableObjectAdministration => context[$mobx];\n","import { onBecomeObserved, onBecomeUnobserved } from 'mobx';\n\n/**\n * Starts side effects only while one or more MobX observables are being observed.\n *\n * When the first property becomes observed, `onStart` is called. When all tracked\n * properties become unobserved, `onEnd` is called with the value returned by\n * `onStart`. Cleanup can be delayed via `endDelay`.\n *\n * It uses MobX `onBecomeObserved` and `onBecomeUnobserved` hooks to perform\n * lazy subscription management.\n *\n * @template TMetaData Data returned from `onStart` and forwarded to `onEnd`.\n * @param config Configuration for tracked properties and lifecycle callbacks.\n * @returns Cleanup function that clears the tracked state and runs `onEnd`.\n *\n * @example\n * ```ts\n * const stop = lazyObserve({\n * context: store,\n * property: 'items',\n * onStart: () => api.subscribe(),\n * onEnd: (subscription) => subscription.unsubscribe(),\n * });\n * ```\n *\n * @example\n * ```ts\n * lazyObserve({\n * property: [boxA, boxB],\n * onStart: () => console.log('observed'),\n * endDelay: 300,\n * });\n * ```\n */\nexport const lazyObserve = <TMetaData = void>({\n context,\n property,\n onStart,\n onEnd,\n endDelay = false,\n}: {\n context?: any;\n property: any | any[];\n onStart?: () => TMetaData;\n onEnd?: (metaData: TMetaData, cleanupFn: VoidFunction) => void;\n endDelay?: number | false;\n}) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let metaData: TMetaData | undefined;\n const observingProps = new Set<string>();\n const properties = Array.isArray(property) ? property : [property];\n\n const cleanup = () => {\n observingProps.clear();\n\n if (endDelay === false) {\n onEnd?.(metaData!, cleanup);\n metaData = undefined;\n return;\n }\n\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n }\n\n timeoutId = setTimeout(() => {\n onEnd?.(metaData!, cleanup);\n timeoutId = undefined;\n metaData = undefined;\n }, endDelay);\n };\n\n const start = (property: string) => {\n const isAlreadyObserving = observingProps.size > 0;\n observingProps.add(property);\n\n if (isAlreadyObserving) {\n return;\n }\n\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n }\n\n metaData = onStart?.();\n };\n\n const stop = (property: string) => {\n const isAlreadyNotObserving = !observingProps.size;\n\n observingProps.delete(property);\n\n const isObserving = observingProps.size > 0;\n\n if (isAlreadyNotObserving || isObserving) {\n return;\n }\n\n cleanup();\n };\n\n properties.forEach((property) => {\n if (context) {\n onBecomeObserved(context, property, () => start(property));\n onBecomeUnobserved(context, property, () => stop(property));\n } else {\n onBecomeObserved(property, () => start(property));\n onBecomeUnobserved(property, () => stop(property));\n }\n });\n\n return cleanup;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"mobx.js","names":[],"sources":["../src/mobx/apply-observable.ts","../src/mobx/create-enhanced-atom.ts","../src/mobx/create-ref.ts","../src/mobx/deep-observable-struct.ts","../src/mobx/get-mobx-administration.ts","../src/mobx/lazy-observe.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * Compact **MobX `makeObservable`** wiring from tuple lists of annotations and keys. Reduces boilerplate\n * when many fields share `observable`, `action`, or `computed` decorators and you want one call site\n * instead of sprawling annotation maps across large stores.\n *\n * ## Usage\n *\n * ```ts\n * import { applyObservable } from \"yummies/mobx\";\n * ```\n */\n\nimport { type AnnotationMapEntry, makeObservable } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\nexport type ObservableAnnotationsArray<T extends AnyObject = AnyObject> = [\n AnnotationMapEntry,\n ...(keyof T | (string & {}))[],\n][];\n\n/**\n * Applies a compact list of MobX annotations to an object using either\n * decorator-style invocation or the annotation map form accepted by `makeObservable`.\n *\n * @template T Target object type.\n * @param context Object that should become observable.\n * @param annotationsArray Tuples of annotation followed by annotated field names.\n * @param useDecorators Enables decorator-style application before calling `makeObservable`.\n *\n * @example\n * ```ts\n * applyObservable(store, [[observable, 'items'], [action, 'setItems']]);\n * ```\n *\n * @example\n * ```ts\n * applyObservable(viewModel, [[computed, 'fullName']], true);\n * ```\n */\nexport const applyObservable = <T extends AnyObject>(\n context: T,\n annotationsArray: ObservableAnnotationsArray<T>,\n useDecorators?: boolean,\n) => {\n if (useDecorators) {\n annotationsArray.forEach(([annotation, ...fields]) => {\n fields.forEach((field) => {\n // @ts-expect-error\n annotation(context, field);\n });\n });\n\n makeObservable(context);\n } else {\n const annotationsObject: AnyObject = {};\n\n annotationsArray.forEach(([annotation, ...fields]) => {\n fields.forEach((field) => {\n annotationsObject[field] = annotation;\n });\n });\n\n makeObservable(context, annotationsObject);\n }\n};\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **`createAtom` wrapper** that attaches arbitrary metadata and keeps MobX’s observed/unobserved\n * hooks in one place. Useful for custom reactive primitives, async resources, or debugging atoms\n * where the stock API is too bare.\n *\n * ## Usage\n *\n * ```ts\n * import { createEnhancedAtom } from \"yummies/mobx\";\n * ```\n */\n\nimport { createAtom, type IAtom } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\nexport interface IEnhancedAtom<TMeta extends AnyObject = AnyObject>\n extends IAtom {\n meta: TMeta;\n}\n\n/**\n * Creates a MobX atom extended with metadata and bound reporting methods.\n *\n * @template TMeta Metadata object stored on the atom.\n * @param name Atom name used by MobX for debugging.\n * @param onBecomeObservedHandler Callback fired when the atom becomes observed.\n * @param onBecomeUnobservedHandler Callback fired when the atom is no longer observed.\n * @param meta Optional metadata attached to the atom.\n * @returns Atom instance with `meta`, `reportChanged` and `reportObserved`.\n *\n * @example\n * ```ts\n * const atom = createEnhancedAtom('user-status');\n * atom.reportChanged();\n * ```\n *\n * @example\n * ```ts\n * const atom = createEnhancedAtom('cache', undefined, undefined, { scope: 'users' });\n * atom.meta.scope;\n * ```\n */\nexport const createEnhancedAtom = <TMeta extends AnyObject>(\n name: string,\n onBecomeObservedHandler?: (atom: IEnhancedAtom<TMeta>) => void,\n onBecomeUnobservedHandler?: (atom: IEnhancedAtom<TMeta>) => void,\n meta?: TMeta,\n): IEnhancedAtom<TMeta> => {\n const atom = createAtom(\n name,\n onBecomeObservedHandler && (() => onBecomeObservedHandler(atom)),\n onBecomeUnobservedHandler && (() => onBecomeUnobservedHandler(atom)),\n ) as IEnhancedAtom<TMeta>;\n atom.meta = meta ?? ({} as TMeta);\n atom.reportChanged = atom.reportChanged.bind(atom);\n atom.reportObserved = atom.reportObserved.bind(atom);\n return atom;\n};\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **Observable ref** pattern for MobX: boxed mutable references with change listeners, metadata,\n * and optional custom equality. Bridges React-style ref holders and MobX reactivity when a single\n * mutable cell must notify dependents without replacing the whole parent object graph.\n *\n * ## Usage\n *\n * ```ts\n * import { createRef } from \"yummies/mobx\";\n * ```\n */\n\nimport {\n type IEqualsComparer,\n makeObservable,\n comparer as mobxComparer,\n observable,\n runInAction,\n} from 'mobx';\nimport type { AnyObject, Maybe } from 'yummies/types';\n\n/**\n * You can return `false` if you don't want to change the value in this ref\n */\nexport type RefChangeListener<T> = (\n value: T | null,\n prevValue: T | undefined,\n) => void | false;\n\n/**\n * Alternative to React.createRef but works in MobX world.\n * Typically it the should be the same React.LegacyRef (fn style)\n */\nexport interface Ref<T = any, TMeta = AnyObject> {\n /**\n * Setter function\n */\n (value: Maybe<T>): void;\n\n set(value: Maybe<T>): void;\n listeners: Set<RefChangeListener<NoInfer<T>>>;\n current: NoInfer<T> | null;\n meta: TMeta;\n}\n\nexport interface CreateRefConfig<T = any, TMeta = AnyObject> {\n onSet?: (node: T, prevValue: T | undefined) => void;\n onUnset?: (lastValue: T | undefined) => void;\n onChange?: RefChangeListener<T>;\n meta?: TMeta;\n initial?: Maybe<T>;\n comparer?: IEqualsComparer<T | null>;\n}\n\n/**\n * Creates a MobX-aware ref that behaves like a callback ref and exposes\n * observable `current` and `meta` fields.\n *\n * @template T Referenced value type.\n * @template TMeta Additional observable metadata stored on the ref.\n * @param cfg Optional callbacks, initial value and comparer configuration.\n * @returns Observable ref function object.\n *\n * @example\n * ```ts\n * const inputRef = createRef<HTMLInputElement>();\n * inputRef.set(document.createElement('input'));\n * ```\n *\n * @example\n * ```ts\n * const ref = createRef<number>();\n * ref(3);\n * ref.current; // 3\n * ```\n *\n * @example\n * ```ts\n * const nodeRef = createRef({\n * onUnset: () => console.log('detached'),\n * meta: { mounted: false },\n * });\n * ```\n */\nexport const createRef = <T = any, TMeta = AnyObject>(\n cfg?: CreateRefConfig<T, TMeta>,\n): Ref<T, TMeta> => {\n let lastValue: T | undefined;\n const comparer = cfg?.comparer ?? mobxComparer.default;\n\n const setValue: Ref<T, TMeta>['set'] = (value) => {\n const nextValue = value ?? null;\n\n if (comparer(ref.current, nextValue)) {\n return;\n }\n\n runInAction(() => {\n const prevLastValue = lastValue;\n lastValue = ref.current ?? undefined;\n ref.current = nextValue;\n\n let isNextValueIgnored = false;\n\n ref.listeners.forEach((listener) => {\n const listenerResult = listener(ref.current, lastValue);\n\n if (listenerResult === false) {\n isNextValueIgnored = true;\n }\n });\n\n if (isNextValueIgnored) {\n lastValue = prevLastValue;\n ref.current = lastValue ?? null;\n } else if (ref.current === null && lastValue !== undefined) {\n lastValue = undefined;\n }\n });\n };\n\n const ref = setValue as Ref<T, TMeta>;\n\n ref.set = setValue;\n\n ref.listeners = new Set(cfg?.onChange ? [cfg.onChange] : []);\n\n if (cfg?.onSet || cfg?.onUnset) {\n ref.listeners.add((value, prevValue) => {\n if (value) {\n cfg.onSet?.(value, prevValue);\n } else {\n cfg.onUnset?.(prevValue);\n }\n });\n }\n\n ref.current = cfg?.initial ?? null;\n ref.meta = cfg?.meta ?? ({} as TMeta);\n\n makeObservable(ref, {\n current: observable.ref,\n meta: observable,\n });\n\n return ref;\n};\n\n/**\n * Checks whether the provided value is a ref created by `createRef`.\n *\n * @template T Referenced value type.\n * @template TMeta Ref metadata type.\n * @param value Value to inspect.\n * @returns `true` when the value is a ref-like function with `current`.\n *\n * @example\n * ```ts\n * const ref = createRef<number>();\n * isRef(ref); // true\n * ```\n *\n * @example\n * ```ts\n * isRef({ current: 1 }); // false\n * ```\n */\nexport const isRef = <T, TMeta = any>(\n value: T | Ref<T, TMeta>,\n): value is Ref<T, TMeta> => {\n return typeof value === 'function' && 'current' in value;\n};\n\n/**\n * Normalizes a plain value or an existing ref into a `Ref` instance.\n *\n * @template T Referenced value type.\n * @template TMeta Ref metadata type.\n * @param value Existing ref or initial plain value.\n * @param cfg Optional ref configuration applied when a new ref is created.\n * @returns Existing ref or a newly created ref initialized with `value`.\n *\n * @example\n * ```ts\n * const ref = toRef(document.body);\n * ref.current === document.body;\n * ```\n *\n * @example\n * ```ts\n * const existingRef = createRef<number>();\n * const sameRef = toRef(existingRef);\n * ```\n */\nexport const toRef = <T, TMeta = any>(\n value: T | Ref<T, TMeta>,\n cfg?: Omit<CreateRefConfig<T, TMeta>, 'initial'>,\n): Ref<T, TMeta> => {\n return isRef(value) ? value : createRef({ initial: value, ...cfg });\n};\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **Deep observable object** with structural `set` patches that reuse nested observables when keys\n * overlap. Helps store trees (forms, filters, entities) under MobX without wholesale replacement\n * and without manual `observable.map` wiring for every level.\n *\n * ## Usage\n *\n * ```ts\n * import { DeepObservableStruct } from \"yummies/mobx\";\n * ```\n */\n\nimport { action, makeObservable, observable } from 'mobx';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { AnyObject } from 'yummies/types';\n\n/**\n * Wraps a plain object into a deeply observable structure and allows\n * patch-like updates while preserving nested observable references where possible.\n *\n * @template TData Observable object shape.\n *\n * @example\n * ```ts\n * const state = new DeepObservableStruct({ user: { name: 'Ann' } });\n * state.set({ user: { name: 'Bob' } });\n * ```\n *\n * @example\n * ```ts\n * const state = new DeepObservableStruct({ filters: { active: true } });\n * state.set({ filters: { active: false, archived: true } });\n * ```\n */\nexport class DeepObservableStruct<TData extends AnyObject> {\n data: TData;\n\n constructor(data: TData) {\n this.data = data;\n\n makeObservable(this, {\n data: observable.deep,\n set: action,\n });\n }\n\n set(newData: Partial<TData>) {\n type StackItem = [key: string, currObservable: AnyObject, new: AnyObject];\n\n const stack: StackItem[] = Object.keys(this.data).map((key) => [\n key,\n this.data,\n newData,\n ]);\n\n let currentIndex = 0;\n let stackLength = stack.length;\n\n while (currentIndex < stackLength) {\n const [key, currObservableData, newData] = stack[currentIndex];\n const newValue = newData[key];\n const currValue = currObservableData[key];\n\n currentIndex++;\n\n if (key in newData) {\n if (typeGuard.isObject(newValue) && typeGuard.isObject(currValue)) {\n const newValueKeys = Object.keys(newValue);\n\n Object.keys(currValue).forEach((childKey) => {\n if (!(childKey in newValue)) {\n delete currObservableData[key][childKey];\n }\n });\n\n newValueKeys.forEach((childKey) => {\n const length = stack.push([\n childKey,\n currObservableData[key],\n newValue,\n ]);\n stackLength = length;\n });\n } else if (newValue !== currValue) {\n currObservableData[key] = newValue;\n }\n } else {\n delete currObservableData[key];\n }\n }\n\n Object.keys(newData).forEach((newDataKey) => {\n if (!this.data[newDataKey]) {\n // @ts-expect-error\n this.data[newDataKey] = newData[newDataKey];\n }\n });\n }\n}\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * Typed access to MobX **internal administration** (`$mobx`) for advanced tooling, migration scripts,\n * or introspection. Prefer public MobX APIs in application code; reach for this when you must align\n * with library internals or patch behavior at the administration layer.\n *\n * ## Usage\n *\n * ```ts\n * import { getMobxAdministration } from \"yummies/mobx\";\n * ```\n */\n\nimport { $mobx, type AnnotationMapEntry } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\ntype ObservableObjectAdministration = Parameters<\n Exclude<AnnotationMapEntry, boolean>['make_']\n>[0];\n\n/**\n * Returns the internal MobX administration object associated with an observable target.\n *\n * @param context Observable object instance.\n * @returns MobX administration internals stored under `$mobx`.\n *\n * @example\n * ```ts\n * const admin = getMobxAdministration(store);\n * admin.name_;\n * ```\n *\n * @example\n * ```ts\n * const values = getMobxAdministration(formState).values_;\n * ```\n */\nexport const getMobxAdministration = (\n context: AnyObject,\n): ObservableObjectAdministration => context[$mobx];\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **Lazy subscriptions** tied to MobX observation: start work when the first reaction observes\n * tracked keys, stop when nothing listens anymore (optionally after a delay). Ideal for polling,\n * WebSocket feeds, or expensive caches that should idle when the UI is not mounted.\n *\n * ## Usage\n *\n * ```ts\n * import { lazyObserve } from \"yummies/mobx\";\n * ```\n */\n\nimport { onBecomeObserved, onBecomeUnobserved } from 'mobx';\n\n/**\n * Starts side effects only while one or more MobX observables are being observed.\n *\n * When the first property becomes observed, `onStart` is called. When all tracked\n * properties become unobserved, `onEnd` is called with the value returned by\n * `onStart`. Cleanup can be delayed via `endDelay`.\n *\n * It uses MobX `onBecomeObserved` and `onBecomeUnobserved` hooks to perform\n * lazy subscription management.\n *\n * @template TMetaData Data returned from `onStart` and forwarded to `onEnd`.\n * @param config Configuration for tracked properties and lifecycle callbacks.\n * @returns Cleanup function that clears the tracked state and runs `onEnd`.\n *\n * @example\n * ```ts\n * const stop = lazyObserve({\n * context: store,\n * property: 'items',\n * onStart: () => api.subscribe(),\n * onEnd: (subscription) => subscription.unsubscribe(),\n * });\n * ```\n *\n * @example\n * ```ts\n * lazyObserve({\n * property: [boxA, boxB],\n * onStart: () => console.log('observed'),\n * endDelay: 300,\n * });\n * ```\n */\nexport const lazyObserve = <TMetaData = void>({\n context,\n property,\n onStart,\n onEnd,\n endDelay = false,\n}: {\n context?: any;\n property: any | any[];\n onStart?: () => TMetaData;\n onEnd?: (metaData: TMetaData, cleanupFn: VoidFunction) => void;\n endDelay?: number | false;\n}) => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let metaData: TMetaData | undefined;\n const observingProps = new Set<string>();\n const properties = Array.isArray(property) ? property : [property];\n\n const cleanup = () => {\n observingProps.clear();\n\n if (endDelay === false) {\n onEnd?.(metaData!, cleanup);\n metaData = undefined;\n return;\n }\n\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n }\n\n timeoutId = setTimeout(() => {\n onEnd?.(metaData!, cleanup);\n timeoutId = undefined;\n metaData = undefined;\n }, endDelay);\n };\n\n const start = (property: string) => {\n const isAlreadyObserving = observingProps.size > 0;\n observingProps.add(property);\n\n if (isAlreadyObserving) {\n return;\n }\n\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n }\n\n metaData = onStart?.();\n };\n\n const stop = (property: string) => {\n const isAlreadyNotObserving = !observingProps.size;\n\n observingProps.delete(property);\n\n const isObserving = observingProps.size > 0;\n\n if (isAlreadyNotObserving || isObserving) {\n return;\n }\n\n cleanup();\n };\n\n properties.forEach((property) => {\n if (context) {\n onBecomeObserved(context, property, () => start(property));\n onBecomeUnobserved(context, property, () => stop(property));\n } else {\n onBecomeObserved(property, () => start(property));\n onBecomeUnobserved(property, () => stop(property));\n }\n });\n\n return cleanup;\n};\n"],"mappings":"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"}
package/ms.cjs CHANGED
@@ -1,5 +1,21 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/ms.ts
3
+ /**
4
+ * ---header-docs-section---
5
+ * # yummies/ms
6
+ *
7
+ * ## Description
8
+ *
9
+ * Converts human-friendly time units (seconds, minutes, hours, days, weeks) to **milliseconds** for
10
+ * timers, animations, and `dayjs`-style math. The `unitsToMs` map is shared across the library so
11
+ * delays and durations stay consistent instead of scattering `* 1000` literals through the code.
12
+ *
13
+ * ## Usage
14
+ *
15
+ * ```ts
16
+ * import { ms } from "yummies/ms";
17
+ * ```
18
+ */
3
19
  var unitsToMs = {
4
20
  ms: 1,
5
21
  sec: 1e3,
package/ms.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ms.cjs","names":[],"sources":["../src/ms.ts"],"sourcesContent":["export const unitsToMs = {\n ms: 1,\n sec: 1000,\n min: 1000 * 60,\n hour: 1000 * 60 * 60,\n day: 1000 * 60 * 60 * 24,\n week: 1000 * 60 * 60 * 24 * 7,\n} as const;\n\n/**\n * Converts a value in the specified unit to milliseconds.\n *\n * @example\n * ```ts\n * ms(1, 'min') // 60_000\n * ms(30, 'sec') // 30_000\n * ```\n */\nexport const ms = (value: number, unit: keyof typeof unitsToMs = 'ms') =>\n value * unitsToMs[unit];\n"],"mappings":";;AAAA,IAAa,YAAY;CACvB,IAAI;CACJ,KAAK;CACL,KAAK,MAAO;CACZ,MAAM,MAAO,KAAK;CAClB,KAAK,MAAO,KAAK,KAAK;CACtB,MAAM,MAAO,KAAK,KAAK,KAAK;CAC7B;;;;;;;;;;AAWD,IAAa,MAAM,OAAe,OAA+B,SAC/D,QAAQ,UAAU"}
1
+ {"version":3,"file":"ms.cjs","names":[],"sources":["../src/ms.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/ms\n *\n * ## Description\n *\n * Converts human-friendly time units (seconds, minutes, hours, days, weeks) to **milliseconds** for\n * timers, animations, and `dayjs`-style math. The `unitsToMs` map is shared across the library so\n * delays and durations stay consistent instead of scattering `* 1000` literals through the code.\n *\n * ## Usage\n *\n * ```ts\n * import { ms } from \"yummies/ms\";\n * ```\n */\n\nexport const unitsToMs = {\n ms: 1,\n sec: 1000,\n min: 1000 * 60,\n hour: 1000 * 60 * 60,\n day: 1000 * 60 * 60 * 24,\n week: 1000 * 60 * 60 * 24 * 7,\n} as const;\n\n/**\n * Converts a value in the specified unit to milliseconds.\n *\n * @example\n * ```ts\n * ms(1, 'min') // 60_000\n * ms(30, 'sec') // 30_000\n * ```\n */\nexport const ms = (value: number, unit: keyof typeof unitsToMs = 'ms') =>\n value * unitsToMs[unit];\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,IAAa,YAAY;CACvB,IAAI;CACJ,KAAK;CACL,KAAK,MAAO;CACZ,MAAM,MAAO,KAAK;CAClB,KAAK,MAAO,KAAK,KAAK;CACtB,MAAM,MAAO,KAAK,KAAK,KAAK;CAC7B;;;;;;;;;;AAWD,IAAa,MAAM,OAAe,OAA+B,SAC/D,QAAQ,UAAU"}
package/ms.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ /**
2
+ * ---header-docs-section---
3
+ * # yummies/ms
4
+ *
5
+ * ## Description
6
+ *
7
+ * Converts human-friendly time units (seconds, minutes, hours, days, weeks) to **milliseconds** for
8
+ * timers, animations, and `dayjs`-style math. The `unitsToMs` map is shared across the library so
9
+ * delays and durations stay consistent instead of scattering `* 1000` literals through the code.
10
+ *
11
+ * ## Usage
12
+ *
13
+ * ```ts
14
+ * import { ms } from "yummies/ms";
15
+ * ```
16
+ */
1
17
  declare const unitsToMs: {
2
18
  readonly ms: 1;
3
19
  readonly sec: 1000;
package/ms.js CHANGED
@@ -1,4 +1,20 @@
1
1
  //#region src/ms.ts
2
+ /**
3
+ * ---header-docs-section---
4
+ * # yummies/ms
5
+ *
6
+ * ## Description
7
+ *
8
+ * Converts human-friendly time units (seconds, minutes, hours, days, weeks) to **milliseconds** for
9
+ * timers, animations, and `dayjs`-style math. The `unitsToMs` map is shared across the library so
10
+ * delays and durations stay consistent instead of scattering `* 1000` literals through the code.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { ms } from "yummies/ms";
16
+ * ```
17
+ */
2
18
  var unitsToMs = {
3
19
  ms: 1,
4
20
  sec: 1e3,
package/ms.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ms.js","names":[],"sources":["../src/ms.ts"],"sourcesContent":["export const unitsToMs = {\n ms: 1,\n sec: 1000,\n min: 1000 * 60,\n hour: 1000 * 60 * 60,\n day: 1000 * 60 * 60 * 24,\n week: 1000 * 60 * 60 * 24 * 7,\n} as const;\n\n/**\n * Converts a value in the specified unit to milliseconds.\n *\n * @example\n * ```ts\n * ms(1, 'min') // 60_000\n * ms(30, 'sec') // 30_000\n * ```\n */\nexport const ms = (value: number, unit: keyof typeof unitsToMs = 'ms') =>\n value * unitsToMs[unit];\n"],"mappings":";AAAA,IAAa,YAAY;CACvB,IAAI;CACJ,KAAK;CACL,KAAK,MAAO;CACZ,MAAM,MAAO,KAAK;CAClB,KAAK,MAAO,KAAK,KAAK;CACtB,MAAM,MAAO,KAAK,KAAK,KAAK;CAC7B;;;;;;;;;;AAWD,IAAa,MAAM,OAAe,OAA+B,SAC/D,QAAQ,UAAU"}
1
+ {"version":3,"file":"ms.js","names":[],"sources":["../src/ms.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/ms\n *\n * ## Description\n *\n * Converts human-friendly time units (seconds, minutes, hours, days, weeks) to **milliseconds** for\n * timers, animations, and `dayjs`-style math. The `unitsToMs` map is shared across the library so\n * delays and durations stay consistent instead of scattering `* 1000` literals through the code.\n *\n * ## Usage\n *\n * ```ts\n * import { ms } from \"yummies/ms\";\n * ```\n */\n\nexport const unitsToMs = {\n ms: 1,\n sec: 1000,\n min: 1000 * 60,\n hour: 1000 * 60 * 60,\n day: 1000 * 60 * 60 * 24,\n week: 1000 * 60 * 60 * 24 * 7,\n} as const;\n\n/**\n * Converts a value in the specified unit to milliseconds.\n *\n * @example\n * ```ts\n * ms(1, 'min') // 60_000\n * ms(30, 'sec') // 30_000\n * ```\n */\nexport const ms = (value: number, unit: keyof typeof unitsToMs = 'ms') =>\n value * unitsToMs[unit];\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,IAAa,YAAY;CACvB,IAAI;CACJ,KAAK;CACL,KAAK,MAAO;CACZ,MAAM,MAAO,KAAK;CAClB,KAAK,MAAO,KAAK,KAAK;CACtB,MAAM,MAAO,KAAK,KAAK,KAAK;CAC7B;;;;;;;;;;AAWD,IAAa,MAAM,OAAe,OAA+B,SAC/D,QAAQ,UAAU"}
package/number.cjs CHANGED
@@ -1,6 +1,22 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/number.ts
3
3
  /**
4
+ * ---header-docs-section---
5
+ * # yummies/number
6
+ *
7
+ * ## Description
8
+ *
9
+ * Numeric rounding that avoids classic floating-point artifacts (`191.212999…`) without paying for
10
+ * string round-trips in hot paths. Use when formatting prices, charts, or sliders where a fixed
11
+ * decimal count must be stable for display and comparisons.
12
+ *
13
+ * ## Usage
14
+ *
15
+ * ```ts
16
+ * import { round } from "yummies/number";
17
+ * ```
18
+ */
19
+ /**
4
20
  * Works like `parseFloat(number.toFixed(4))` but performance better
5
21
  *
6
22
  * @example
package/number.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"number.cjs","names":[],"sources":["../src/number.ts"],"sourcesContent":["/**\n * Works like `parseFloat(number.toFixed(4))` but performance better\n *\n * @example\n * round(191.212999999999999999999999, 4) // 191.213\n */\nexport function round(value: number, decimalPlaces: number = 0): number {\n if (!decimalPlaces) {\n return Math.round(value);\n }\n\n const factor = 10 ** decimalPlaces;\n return Math.round(value * factor) / factor;\n}\n"],"mappings":";;;;;;;;AAMA,SAAgB,MAAM,OAAe,gBAAwB,GAAW;AACtE,KAAI,CAAC,cACH,QAAO,KAAK,MAAM,MAAM;CAG1B,MAAM,SAAS,MAAM;AACrB,QAAO,KAAK,MAAM,QAAQ,OAAO,GAAG"}
1
+ {"version":3,"file":"number.cjs","names":[],"sources":["../src/number.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/number\n *\n * ## Description\n *\n * Numeric rounding that avoids classic floating-point artifacts (`191.212999…`) without paying for\n * string round-trips in hot paths. Use when formatting prices, charts, or sliders where a fixed\n * decimal count must be stable for display and comparisons.\n *\n * ## Usage\n *\n * ```ts\n * import { round } from \"yummies/number\";\n * ```\n */\n\n/**\n * Works like `parseFloat(number.toFixed(4))` but performance better\n *\n * @example\n * round(191.212999999999999999999999, 4) // 191.213\n */\nexport function round(value: number, decimalPlaces: number = 0): number {\n if (!decimalPlaces) {\n return Math.round(value);\n }\n\n const factor = 10 ** decimalPlaces;\n return Math.round(value * factor) / factor;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,MAAM,OAAe,gBAAwB,GAAW;AACtE,KAAI,CAAC,cACH,QAAO,KAAK,MAAM,MAAM;CAG1B,MAAM,SAAS,MAAM;AACrB,QAAO,KAAK,MAAM,QAAQ,OAAO,GAAG"}
package/number.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ /**
2
+ * ---header-docs-section---
3
+ * # yummies/number
4
+ *
5
+ * ## Description
6
+ *
7
+ * Numeric rounding that avoids classic floating-point artifacts (`191.212999…`) without paying for
8
+ * string round-trips in hot paths. Use when formatting prices, charts, or sliders where a fixed
9
+ * decimal count must be stable for display and comparisons.
10
+ *
11
+ * ## Usage
12
+ *
13
+ * ```ts
14
+ * import { round } from "yummies/number";
15
+ * ```
16
+ */
1
17
  /**
2
18
  * Works like `parseFloat(number.toFixed(4))` but performance better
3
19
  *
package/number.js CHANGED
@@ -1,5 +1,21 @@
1
1
  //#region src/number.ts
2
2
  /**
3
+ * ---header-docs-section---
4
+ * # yummies/number
5
+ *
6
+ * ## Description
7
+ *
8
+ * Numeric rounding that avoids classic floating-point artifacts (`191.212999…`) without paying for
9
+ * string round-trips in hot paths. Use when formatting prices, charts, or sliders where a fixed
10
+ * decimal count must be stable for display and comparisons.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { round } from "yummies/number";
16
+ * ```
17
+ */
18
+ /**
3
19
  * Works like `parseFloat(number.toFixed(4))` but performance better
4
20
  *
5
21
  * @example
package/number.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"number.js","names":[],"sources":["../src/number.ts"],"sourcesContent":["/**\n * Works like `parseFloat(number.toFixed(4))` but performance better\n *\n * @example\n * round(191.212999999999999999999999, 4) // 191.213\n */\nexport function round(value: number, decimalPlaces: number = 0): number {\n if (!decimalPlaces) {\n return Math.round(value);\n }\n\n const factor = 10 ** decimalPlaces;\n return Math.round(value * factor) / factor;\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,MAAM,OAAe,gBAAwB,GAAW;AACtE,KAAI,CAAC,cACH,QAAO,KAAK,MAAM,MAAM;CAG1B,MAAM,SAAS,MAAM;AACrB,QAAO,KAAK,MAAM,QAAQ,OAAO,GAAG"}
1
+ {"version":3,"file":"number.js","names":[],"sources":["../src/number.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/number\n *\n * ## Description\n *\n * Numeric rounding that avoids classic floating-point artifacts (`191.212999…`) without paying for\n * string round-trips in hot paths. Use when formatting prices, charts, or sliders where a fixed\n * decimal count must be stable for display and comparisons.\n *\n * ## Usage\n *\n * ```ts\n * import { round } from \"yummies/number\";\n * ```\n */\n\n/**\n * Works like `parseFloat(number.toFixed(4))` but performance better\n *\n * @example\n * round(191.212999999999999999999999, 4) // 191.213\n */\nexport function round(value: number, decimalPlaces: number = 0): number {\n if (!decimalPlaces) {\n return Math.round(value);\n }\n\n const factor = 10 ** decimalPlaces;\n return Math.round(value * factor) / factor;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,MAAM,OAAe,gBAAwB,GAAW;AACtE,KAAI,CAAC,cACH,QAAO,KAAK,MAAM,MAAM;CAG1B,MAAM,SAAS,MAAM;AACrB,QAAO,KAAK,MAAM,QAAQ,OAAO,GAAG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yummies",
3
- "version": "7.12.0",
3
+ "version": "7.13.0",
4
4
  "keywords": [
5
5
  "javascript",
6
6
  "typescript",
@@ -12,7 +12,7 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/js2me/yummies/issues"
14
14
  },
15
- "homepage": "https://github.com/js2me/yummies",
15
+ "homepage": "https://js2me.github.io/yummies/api/async/",
16
16
  "repository": {
17
17
  "type": "git",
18
18
  "url": "git://github.com/js2me/yummies"
package/parser.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"parser.cjs","names":[],"sources":["../src/parser/number.ts","../src/parser/percent.ts","../src/parser/string.ts","../src/parser/_exports.ts"],"sourcesContent":["import { format } from 'yummies/format';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface NumberParserSettings<TFallback = number> {\n digits?: number;\n fallback?: TFallback;\n /**\n * Round to upper boundary\n * 5.1 -> 6\n */\n ceil?: boolean;\n /**\n * Round to bottom boundary\n * 5.9 -> 5\n */\n floor?: boolean;\n clamped?: [min?: Maybe<number>, max?: Maybe<number>];\n}\n\n/**\n * Parses a number from raw input and optionally clamps, rounds or limits\n * fractional digits.\n *\n * Strings are normalized by removing spaces and replacing `,` with `.` before\n * parsing. Invalid inputs return the configured fallback.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param input Raw value to parse.\n * @param userSettings Parser settings merged with `number.defaultSettings`.\n * @returns Parsed number or fallback value.\n *\n * @example\n * ```ts\n * number('1 234,5'); // 1234.5\n * ```\n *\n * @example\n * ```ts\n * number('bad', { fallback: 0 }); // 0\n * ```\n */\nexport const number = <TFallback = number>(\n input: Maybe<unknown>,\n userSettings?: Maybe<NumberParserSettings<TFallback>>,\n): number | TFallback => {\n const settings = {\n ...number.defaultSettings,\n ...userSettings,\n };\n\n const fallback = (\n 'fallback' in settings ? settings.fallback : 0\n ) as TFallback;\n\n let result: number;\n\n if (typeGuard.isNumber(input)) {\n result = input;\n } else if (typeGuard.isString(input)) {\n const formattedInput = format.skipSpaces(input).replace(',', '.');\n if (formattedInput === '') {\n result = fallback as any;\n } else {\n result = Number(formattedInput);\n }\n } else {\n result = fallback as any;\n }\n\n if (typeGuard.isNumber(result)) {\n if (settings?.clamped != null) {\n result = Math.max(\n settings.clamped[0] ?? -Infinity,\n Math.min(result, settings.clamped[1] ?? Infinity),\n );\n }\n\n if (settings?.ceil != null) {\n result = Math.ceil(result);\n }\n\n if (settings?.floor != null) {\n result = Math.floor(result);\n }\n\n if (settings?.digits != null) {\n result = +result.toFixed(settings.digits);\n }\n\n return result;\n } else {\n return fallback;\n }\n};\n\nnumber.defaultSettings = {} as NumberParserSettings;\n","import type { Maybe } from 'yummies/types';\n\nimport { type NumberParserSettings, number } from './number.js';\n\n/**\n * Converts a value into a percentage of `maxValue` and parses the result with\n * the shared numeric parser.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param value Current value.\n * @param maxValue Maximum value representing `100%`.\n * @param settings Numeric parser settings for the computed percentage.\n * @returns Parsed percentage or fallback value.\n *\n * @example\n * ```ts\n * percent(25, 200); // 12.5\n * ```\n *\n * @example\n * ```ts\n * percent('bad', 100, { fallback: 0 }); // 0\n * ```\n */\nexport const percent = <TFallback = number>(\n value: Maybe<string | number>,\n maxValue?: Maybe<string | number>,\n settings?: Maybe<NumberParserSettings<TFallback>>,\n) => {\n return number<TFallback>((Number(value) / Number(maxValue)) * 100, settings);\n};\n","import { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface StringParserSettings<TFallback = string> {\n fallback?: TFallback;\n prettyJson?: boolean;\n}\n\n/**\n * Converts arbitrary input into a string representation.\n *\n * Objects are serialized with `JSON.stringify`, optionally pretty-printed, and\n * nullish values resolve to the configured fallback.\n *\n * @template TFallback Fallback value type returned for nullish input.\n * @param input Raw value to stringify.\n * @param settings String conversion settings.\n * @returns Stringified input or fallback value.\n *\n * @example\n * ```ts\n * string(123); // '123'\n * ```\n *\n * @example\n * ```ts\n * string({ id: 1 }, { prettyJson: true });\n * ```\n */\nexport const string = <TFallback = string>(\n input: Maybe<unknown>,\n settings?: Maybe<StringParserSettings<TFallback>>,\n): string | TFallback => {\n const fallback =\n settings && 'fallback' in settings ? (settings.fallback as TFallback) : '';\n\n if (input == null) {\n return fallback;\n }\n\n if (typeGuard.isObject(input)) {\n if (settings?.prettyJson) {\n return JSON.stringify(input, null, 2);\n }\n\n return JSON.stringify(input);\n }\n\n return String(input);\n};\n","export * from './number.js';\nexport * from './percent.js';\nexport * from './string.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,UACX,OACA,iBACuB;CACvB,MAAM,WAAW;EACf,GAAG,OAAO;EACV,GAAG;EACJ;CAED,MAAM,WACJ,cAAc,WAAW,SAAS,WAAW;CAG/C,IAAI;AAEJ,KAAI,mBAAA,UAAU,SAAS,MAAM,CAC3B,UAAS;UACA,mBAAA,UAAU,SAAS,MAAM,EAAE;EACpC,MAAM,iBAAiB,eAAA,OAAO,WAAW,MAAM,CAAC,QAAQ,KAAK,IAAI;AACjE,MAAI,mBAAmB,GACrB,UAAS;MAET,UAAS,OAAO,eAAe;OAGjC,UAAS;AAGX,KAAI,mBAAA,UAAU,SAAS,OAAO,EAAE;AAC9B,MAAI,UAAU,WAAW,KACvB,UAAS,KAAK,IACZ,SAAS,QAAQ,MAAM,WACvB,KAAK,IAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,CAClD;AAGH,MAAI,UAAU,QAAQ,KACpB,UAAS,KAAK,KAAK,OAAO;AAG5B,MAAI,UAAU,SAAS,KACrB,UAAS,KAAK,MAAM,OAAO;AAG7B,MAAI,UAAU,UAAU,KACtB,UAAS,CAAC,OAAO,QAAQ,SAAS,OAAO;AAG3C,SAAO;OAEP,QAAO;;AAIX,OAAO,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;;;;;ACxE3B,IAAa,WACX,OACA,UACA,aACG;AACH,QAAO,OAAmB,OAAO,MAAM,GAAG,OAAO,SAAS,GAAI,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;ACA9E,IAAa,UACX,OACA,aACuB;CACvB,MAAM,WACJ,YAAY,cAAc,WAAY,SAAS,WAAyB;AAE1E,KAAI,SAAS,KACX,QAAO;AAGT,KAAI,mBAAA,UAAU,SAAS,MAAM,EAAE;AAC7B,MAAI,UAAU,WACZ,QAAO,KAAK,UAAU,OAAO,MAAM,EAAE;AAGvC,SAAO,KAAK,UAAU,MAAM;;AAG9B,QAAO,OAAO,MAAM"}
1
+ {"version":3,"file":"parser.cjs","names":[],"sources":["../src/parser/number.ts","../src/parser/percent.ts","../src/parser/string.ts","../src/parser/_exports.ts"],"sourcesContent":["import { format } from 'yummies/format';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface NumberParserSettings<TFallback = number> {\n digits?: number;\n fallback?: TFallback;\n /**\n * Round to upper boundary\n * 5.1 -> 6\n */\n ceil?: boolean;\n /**\n * Round to bottom boundary\n * 5.9 -> 5\n */\n floor?: boolean;\n clamped?: [min?: Maybe<number>, max?: Maybe<number>];\n}\n\n/**\n * Parses a number from raw input and optionally clamps, rounds or limits\n * fractional digits.\n *\n * Strings are normalized by removing spaces and replacing `,` with `.` before\n * parsing. Invalid inputs return the configured fallback.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param input Raw value to parse.\n * @param userSettings Parser settings merged with `number.defaultSettings`.\n * @returns Parsed number or fallback value.\n *\n * @example\n * ```ts\n * number('1 234,5'); // 1234.5\n * ```\n *\n * @example\n * ```ts\n * number('bad', { fallback: 0 }); // 0\n * ```\n */\nexport const number = <TFallback = number>(\n input: Maybe<unknown>,\n userSettings?: Maybe<NumberParserSettings<TFallback>>,\n): number | TFallback => {\n const settings = {\n ...number.defaultSettings,\n ...userSettings,\n };\n\n const fallback = (\n 'fallback' in settings ? settings.fallback : 0\n ) as TFallback;\n\n let result: number;\n\n if (typeGuard.isNumber(input)) {\n result = input;\n } else if (typeGuard.isString(input)) {\n const formattedInput = format.skipSpaces(input).replace(',', '.');\n if (formattedInput === '') {\n result = fallback as any;\n } else {\n result = Number(formattedInput);\n }\n } else {\n result = fallback as any;\n }\n\n if (typeGuard.isNumber(result)) {\n if (settings?.clamped != null) {\n result = Math.max(\n settings.clamped[0] ?? -Infinity,\n Math.min(result, settings.clamped[1] ?? Infinity),\n );\n }\n\n if (settings?.ceil != null) {\n result = Math.ceil(result);\n }\n\n if (settings?.floor != null) {\n result = Math.floor(result);\n }\n\n if (settings?.digits != null) {\n result = +result.toFixed(settings.digits);\n }\n\n return result;\n } else {\n return fallback;\n }\n};\n\nnumber.defaultSettings = {} as NumberParserSettings;\n","import type { Maybe } from 'yummies/types';\n\nimport { type NumberParserSettings, number } from './number.js';\n\n/**\n * Converts a value into a percentage of `maxValue` and parses the result with\n * the shared numeric parser.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param value Current value.\n * @param maxValue Maximum value representing `100%`.\n * @param settings Numeric parser settings for the computed percentage.\n * @returns Parsed percentage or fallback value.\n *\n * @example\n * ```ts\n * percent(25, 200); // 12.5\n * ```\n *\n * @example\n * ```ts\n * percent('bad', 100, { fallback: 0 }); // 0\n * ```\n */\nexport const percent = <TFallback = number>(\n value: Maybe<string | number>,\n maxValue?: Maybe<string | number>,\n settings?: Maybe<NumberParserSettings<TFallback>>,\n) => {\n return number<TFallback>((Number(value) / Number(maxValue)) * 100, settings);\n};\n","import { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface StringParserSettings<TFallback = string> {\n fallback?: TFallback;\n prettyJson?: boolean;\n}\n\n/**\n * Converts arbitrary input into a string representation.\n *\n * Objects are serialized with `JSON.stringify`, optionally pretty-printed, and\n * nullish values resolve to the configured fallback.\n *\n * @template TFallback Fallback value type returned for nullish input.\n * @param input Raw value to stringify.\n * @param settings String conversion settings.\n * @returns Stringified input or fallback value.\n *\n * @example\n * ```ts\n * string(123); // '123'\n * ```\n *\n * @example\n * ```ts\n * string({ id: 1 }, { prettyJson: true });\n * ```\n */\nexport const string = <TFallback = string>(\n input: Maybe<unknown>,\n settings?: Maybe<StringParserSettings<TFallback>>,\n): string | TFallback => {\n const fallback =\n settings && 'fallback' in settings ? (settings.fallback as TFallback) : '';\n\n if (input == null) {\n return fallback;\n }\n\n if (typeGuard.isObject(input)) {\n if (settings?.prettyJson) {\n return JSON.stringify(input, null, 2);\n }\n\n return JSON.stringify(input);\n }\n\n return String(input);\n};\n","/**\n * ---header-docs-section---\n * # yummies/parser\n *\n * ## Description\n *\n * Parsers for user-entered **numbers, percents, and strings** with tolerant input and typed\n * results. Use when normalizing form values, query params, or CSV-like text before validation\n * schemas run, without duplicating regex and `parseFloat` edge cases in every feature module.\n *\n * ## Usage\n *\n * ```ts\n * import { parser } from \"yummies/parser\";\n * ```\n */\n\nexport * from './number.js';\nexport * from './percent.js';\nexport * from './string.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,UACX,OACA,iBACuB;CACvB,MAAM,WAAW;EACf,GAAG,OAAO;EACV,GAAG;EACJ;CAED,MAAM,WACJ,cAAc,WAAW,SAAS,WAAW;CAG/C,IAAI;AAEJ,KAAI,mBAAA,UAAU,SAAS,MAAM,CAC3B,UAAS;UACA,mBAAA,UAAU,SAAS,MAAM,EAAE;EACpC,MAAM,iBAAiB,eAAA,OAAO,WAAW,MAAM,CAAC,QAAQ,KAAK,IAAI;AACjE,MAAI,mBAAmB,GACrB,UAAS;MAET,UAAS,OAAO,eAAe;OAGjC,UAAS;AAGX,KAAI,mBAAA,UAAU,SAAS,OAAO,EAAE;AAC9B,MAAI,UAAU,WAAW,KACvB,UAAS,KAAK,IACZ,SAAS,QAAQ,MAAM,WACvB,KAAK,IAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,CAClD;AAGH,MAAI,UAAU,QAAQ,KACpB,UAAS,KAAK,KAAK,OAAO;AAG5B,MAAI,UAAU,SAAS,KACrB,UAAS,KAAK,MAAM,OAAO;AAG7B,MAAI,UAAU,UAAU,KACtB,UAAS,CAAC,OAAO,QAAQ,SAAS,OAAO;AAG3C,SAAO;OAEP,QAAO;;AAIX,OAAO,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;;;;;ACxE3B,IAAa,WACX,OACA,UACA,aACG;AACH,QAAO,OAAmB,OAAO,MAAM,GAAG,OAAO,SAAS,GAAI,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;ACA9E,IAAa,UACX,OACA,aACuB;CACvB,MAAM,WACJ,YAAY,cAAc,WAAY,SAAS,WAAyB;AAE1E,KAAI,SAAS,KACX,QAAO;AAGT,KAAI,mBAAA,UAAU,SAAS,MAAM,EAAE;AAC7B,MAAI,UAAU,WACZ,QAAO,KAAK,UAAU,OAAO,MAAM,EAAE;AAGvC,SAAO,KAAK,UAAU,MAAM;;AAG9B,QAAO,OAAO,MAAM"}
package/parser.d.ts CHANGED
@@ -91,6 +91,23 @@ interface StringParserSettings<TFallback = string> {
91
91
  */
92
92
  declare const string: <TFallback = string>(input: Maybe<unknown>, settings?: Maybe<StringParserSettings<TFallback>>) => string | TFallback;
93
93
 
94
+ /**
95
+ * ---header-docs-section---
96
+ * # yummies/parser
97
+ *
98
+ * ## Description
99
+ *
100
+ * Parsers for user-entered **numbers, percents, and strings** with tolerant input and typed
101
+ * results. Use when normalizing form values, query params, or CSV-like text before validation
102
+ * schemas run, without duplicating regex and `parseFloat` edge cases in every feature module.
103
+ *
104
+ * ## Usage
105
+ *
106
+ * ```ts
107
+ * import { parser } from "yummies/parser";
108
+ * ```
109
+ */
110
+
94
111
  type _exports_NumberParserSettings<TFallback = number> = NumberParserSettings<TFallback>;
95
112
  type _exports_StringParserSettings<TFallback = string> = StringParserSettings<TFallback>;
96
113
  declare const _exports_number: typeof number;
package/parser.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","names":[],"sources":["../src/parser/number.ts","../src/parser/percent.ts","../src/parser/string.ts","../src/parser/_exports.ts"],"sourcesContent":["import { format } from 'yummies/format';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface NumberParserSettings<TFallback = number> {\n digits?: number;\n fallback?: TFallback;\n /**\n * Round to upper boundary\n * 5.1 -> 6\n */\n ceil?: boolean;\n /**\n * Round to bottom boundary\n * 5.9 -> 5\n */\n floor?: boolean;\n clamped?: [min?: Maybe<number>, max?: Maybe<number>];\n}\n\n/**\n * Parses a number from raw input and optionally clamps, rounds or limits\n * fractional digits.\n *\n * Strings are normalized by removing spaces and replacing `,` with `.` before\n * parsing. Invalid inputs return the configured fallback.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param input Raw value to parse.\n * @param userSettings Parser settings merged with `number.defaultSettings`.\n * @returns Parsed number or fallback value.\n *\n * @example\n * ```ts\n * number('1 234,5'); // 1234.5\n * ```\n *\n * @example\n * ```ts\n * number('bad', { fallback: 0 }); // 0\n * ```\n */\nexport const number = <TFallback = number>(\n input: Maybe<unknown>,\n userSettings?: Maybe<NumberParserSettings<TFallback>>,\n): number | TFallback => {\n const settings = {\n ...number.defaultSettings,\n ...userSettings,\n };\n\n const fallback = (\n 'fallback' in settings ? settings.fallback : 0\n ) as TFallback;\n\n let result: number;\n\n if (typeGuard.isNumber(input)) {\n result = input;\n } else if (typeGuard.isString(input)) {\n const formattedInput = format.skipSpaces(input).replace(',', '.');\n if (formattedInput === '') {\n result = fallback as any;\n } else {\n result = Number(formattedInput);\n }\n } else {\n result = fallback as any;\n }\n\n if (typeGuard.isNumber(result)) {\n if (settings?.clamped != null) {\n result = Math.max(\n settings.clamped[0] ?? -Infinity,\n Math.min(result, settings.clamped[1] ?? Infinity),\n );\n }\n\n if (settings?.ceil != null) {\n result = Math.ceil(result);\n }\n\n if (settings?.floor != null) {\n result = Math.floor(result);\n }\n\n if (settings?.digits != null) {\n result = +result.toFixed(settings.digits);\n }\n\n return result;\n } else {\n return fallback;\n }\n};\n\nnumber.defaultSettings = {} as NumberParserSettings;\n","import type { Maybe } from 'yummies/types';\n\nimport { type NumberParserSettings, number } from './number.js';\n\n/**\n * Converts a value into a percentage of `maxValue` and parses the result with\n * the shared numeric parser.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param value Current value.\n * @param maxValue Maximum value representing `100%`.\n * @param settings Numeric parser settings for the computed percentage.\n * @returns Parsed percentage or fallback value.\n *\n * @example\n * ```ts\n * percent(25, 200); // 12.5\n * ```\n *\n * @example\n * ```ts\n * percent('bad', 100, { fallback: 0 }); // 0\n * ```\n */\nexport const percent = <TFallback = number>(\n value: Maybe<string | number>,\n maxValue?: Maybe<string | number>,\n settings?: Maybe<NumberParserSettings<TFallback>>,\n) => {\n return number<TFallback>((Number(value) / Number(maxValue)) * 100, settings);\n};\n","import { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface StringParserSettings<TFallback = string> {\n fallback?: TFallback;\n prettyJson?: boolean;\n}\n\n/**\n * Converts arbitrary input into a string representation.\n *\n * Objects are serialized with `JSON.stringify`, optionally pretty-printed, and\n * nullish values resolve to the configured fallback.\n *\n * @template TFallback Fallback value type returned for nullish input.\n * @param input Raw value to stringify.\n * @param settings String conversion settings.\n * @returns Stringified input or fallback value.\n *\n * @example\n * ```ts\n * string(123); // '123'\n * ```\n *\n * @example\n * ```ts\n * string({ id: 1 }, { prettyJson: true });\n * ```\n */\nexport const string = <TFallback = string>(\n input: Maybe<unknown>,\n settings?: Maybe<StringParserSettings<TFallback>>,\n): string | TFallback => {\n const fallback =\n settings && 'fallback' in settings ? (settings.fallback as TFallback) : '';\n\n if (input == null) {\n return fallback;\n }\n\n if (typeGuard.isObject(input)) {\n if (settings?.prettyJson) {\n return JSON.stringify(input, null, 2);\n }\n\n return JSON.stringify(input);\n }\n\n return String(input);\n};\n","export * from './number.js';\nexport * from './percent.js';\nexport * from './string.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,UACX,OACA,iBACuB;CACvB,MAAM,WAAW;EACf,GAAG,OAAO;EACV,GAAG;EACJ;CAED,MAAM,WACJ,cAAc,WAAW,SAAS,WAAW;CAG/C,IAAI;AAEJ,KAAI,UAAU,SAAS,MAAM,CAC3B,UAAS;UACA,UAAU,SAAS,MAAM,EAAE;EACpC,MAAM,iBAAiB,OAAO,WAAW,MAAM,CAAC,QAAQ,KAAK,IAAI;AACjE,MAAI,mBAAmB,GACrB,UAAS;MAET,UAAS,OAAO,eAAe;OAGjC,UAAS;AAGX,KAAI,UAAU,SAAS,OAAO,EAAE;AAC9B,MAAI,UAAU,WAAW,KACvB,UAAS,KAAK,IACZ,SAAS,QAAQ,MAAM,WACvB,KAAK,IAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,CAClD;AAGH,MAAI,UAAU,QAAQ,KACpB,UAAS,KAAK,KAAK,OAAO;AAG5B,MAAI,UAAU,SAAS,KACrB,UAAS,KAAK,MAAM,OAAO;AAG7B,MAAI,UAAU,UAAU,KACtB,UAAS,CAAC,OAAO,QAAQ,SAAS,OAAO;AAG3C,SAAO;OAEP,QAAO;;AAIX,OAAO,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;;;;;ACxE3B,IAAa,WACX,OACA,UACA,aACG;AACH,QAAO,OAAmB,OAAO,MAAM,GAAG,OAAO,SAAS,GAAI,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;ACA9E,IAAa,UACX,OACA,aACuB;CACvB,MAAM,WACJ,YAAY,cAAc,WAAY,SAAS,WAAyB;AAE1E,KAAI,SAAS,KACX,QAAO;AAGT,KAAI,UAAU,SAAS,MAAM,EAAE;AAC7B,MAAI,UAAU,WACZ,QAAO,KAAK,UAAU,OAAO,MAAM,EAAE;AAGvC,SAAO,KAAK,UAAU,MAAM;;AAG9B,QAAO,OAAO,MAAM"}
1
+ {"version":3,"file":"parser.js","names":[],"sources":["../src/parser/number.ts","../src/parser/percent.ts","../src/parser/string.ts","../src/parser/_exports.ts"],"sourcesContent":["import { format } from 'yummies/format';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface NumberParserSettings<TFallback = number> {\n digits?: number;\n fallback?: TFallback;\n /**\n * Round to upper boundary\n * 5.1 -> 6\n */\n ceil?: boolean;\n /**\n * Round to bottom boundary\n * 5.9 -> 5\n */\n floor?: boolean;\n clamped?: [min?: Maybe<number>, max?: Maybe<number>];\n}\n\n/**\n * Parses a number from raw input and optionally clamps, rounds or limits\n * fractional digits.\n *\n * Strings are normalized by removing spaces and replacing `,` with `.` before\n * parsing. Invalid inputs return the configured fallback.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param input Raw value to parse.\n * @param userSettings Parser settings merged with `number.defaultSettings`.\n * @returns Parsed number or fallback value.\n *\n * @example\n * ```ts\n * number('1 234,5'); // 1234.5\n * ```\n *\n * @example\n * ```ts\n * number('bad', { fallback: 0 }); // 0\n * ```\n */\nexport const number = <TFallback = number>(\n input: Maybe<unknown>,\n userSettings?: Maybe<NumberParserSettings<TFallback>>,\n): number | TFallback => {\n const settings = {\n ...number.defaultSettings,\n ...userSettings,\n };\n\n const fallback = (\n 'fallback' in settings ? settings.fallback : 0\n ) as TFallback;\n\n let result: number;\n\n if (typeGuard.isNumber(input)) {\n result = input;\n } else if (typeGuard.isString(input)) {\n const formattedInput = format.skipSpaces(input).replace(',', '.');\n if (formattedInput === '') {\n result = fallback as any;\n } else {\n result = Number(formattedInput);\n }\n } else {\n result = fallback as any;\n }\n\n if (typeGuard.isNumber(result)) {\n if (settings?.clamped != null) {\n result = Math.max(\n settings.clamped[0] ?? -Infinity,\n Math.min(result, settings.clamped[1] ?? Infinity),\n );\n }\n\n if (settings?.ceil != null) {\n result = Math.ceil(result);\n }\n\n if (settings?.floor != null) {\n result = Math.floor(result);\n }\n\n if (settings?.digits != null) {\n result = +result.toFixed(settings.digits);\n }\n\n return result;\n } else {\n return fallback;\n }\n};\n\nnumber.defaultSettings = {} as NumberParserSettings;\n","import type { Maybe } from 'yummies/types';\n\nimport { type NumberParserSettings, number } from './number.js';\n\n/**\n * Converts a value into a percentage of `maxValue` and parses the result with\n * the shared numeric parser.\n *\n * @template TFallback Fallback value type returned when parsing fails.\n * @param value Current value.\n * @param maxValue Maximum value representing `100%`.\n * @param settings Numeric parser settings for the computed percentage.\n * @returns Parsed percentage or fallback value.\n *\n * @example\n * ```ts\n * percent(25, 200); // 12.5\n * ```\n *\n * @example\n * ```ts\n * percent('bad', 100, { fallback: 0 }); // 0\n * ```\n */\nexport const percent = <TFallback = number>(\n value: Maybe<string | number>,\n maxValue?: Maybe<string | number>,\n settings?: Maybe<NumberParserSettings<TFallback>>,\n) => {\n return number<TFallback>((Number(value) / Number(maxValue)) * 100, settings);\n};\n","import { typeGuard } from 'yummies/type-guard';\nimport type { Maybe } from 'yummies/types';\n\nexport interface StringParserSettings<TFallback = string> {\n fallback?: TFallback;\n prettyJson?: boolean;\n}\n\n/**\n * Converts arbitrary input into a string representation.\n *\n * Objects are serialized with `JSON.stringify`, optionally pretty-printed, and\n * nullish values resolve to the configured fallback.\n *\n * @template TFallback Fallback value type returned for nullish input.\n * @param input Raw value to stringify.\n * @param settings String conversion settings.\n * @returns Stringified input or fallback value.\n *\n * @example\n * ```ts\n * string(123); // '123'\n * ```\n *\n * @example\n * ```ts\n * string({ id: 1 }, { prettyJson: true });\n * ```\n */\nexport const string = <TFallback = string>(\n input: Maybe<unknown>,\n settings?: Maybe<StringParserSettings<TFallback>>,\n): string | TFallback => {\n const fallback =\n settings && 'fallback' in settings ? (settings.fallback as TFallback) : '';\n\n if (input == null) {\n return fallback;\n }\n\n if (typeGuard.isObject(input)) {\n if (settings?.prettyJson) {\n return JSON.stringify(input, null, 2);\n }\n\n return JSON.stringify(input);\n }\n\n return String(input);\n};\n","/**\n * ---header-docs-section---\n * # yummies/parser\n *\n * ## Description\n *\n * Parsers for user-entered **numbers, percents, and strings** with tolerant input and typed\n * results. Use when normalizing form values, query params, or CSV-like text before validation\n * schemas run, without duplicating regex and `parseFloat` edge cases in every feature module.\n *\n * ## Usage\n *\n * ```ts\n * import { parser } from \"yummies/parser\";\n * ```\n */\n\nexport * from './number.js';\nexport * from './percent.js';\nexport * from './string.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,UACX,OACA,iBACuB;CACvB,MAAM,WAAW;EACf,GAAG,OAAO;EACV,GAAG;EACJ;CAED,MAAM,WACJ,cAAc,WAAW,SAAS,WAAW;CAG/C,IAAI;AAEJ,KAAI,UAAU,SAAS,MAAM,CAC3B,UAAS;UACA,UAAU,SAAS,MAAM,EAAE;EACpC,MAAM,iBAAiB,OAAO,WAAW,MAAM,CAAC,QAAQ,KAAK,IAAI;AACjE,MAAI,mBAAmB,GACrB,UAAS;MAET,UAAS,OAAO,eAAe;OAGjC,UAAS;AAGX,KAAI,UAAU,SAAS,OAAO,EAAE;AAC9B,MAAI,UAAU,WAAW,KACvB,UAAS,KAAK,IACZ,SAAS,QAAQ,MAAM,WACvB,KAAK,IAAI,QAAQ,SAAS,QAAQ,MAAM,SAAS,CAClD;AAGH,MAAI,UAAU,QAAQ,KACpB,UAAS,KAAK,KAAK,OAAO;AAG5B,MAAI,UAAU,SAAS,KACrB,UAAS,KAAK,MAAM,OAAO;AAG7B,MAAI,UAAU,UAAU,KACtB,UAAS,CAAC,OAAO,QAAQ,SAAS,OAAO;AAG3C,SAAO;OAEP,QAAO;;AAIX,OAAO,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;;;;;ACxE3B,IAAa,WACX,OACA,UACA,aACG;AACH,QAAO,OAAmB,OAAO,MAAM,GAAG,OAAO,SAAS,GAAI,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;ACA9E,IAAa,UACX,OACA,aACuB;CACvB,MAAM,WACJ,YAAY,cAAc,WAAY,SAAS,WAAyB;AAE1E,KAAI,SAAS,KACX,QAAO;AAGT,KAAI,UAAU,SAAS,MAAM,EAAE;AAC7B,MAAI,UAAU,WACZ,QAAO,KAAK,UAAU,OAAO,MAAM,EAAE;AAGvC,SAAO,KAAK,UAAU,MAAM;;AAG9B,QAAO,OAAO,MAAM"}
package/price.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"price.cjs","names":[],"sources":["../src/price.ts"],"sourcesContent":["export interface PriceFormatOptions\n extends Partial<Omit<Intl.NumberFormatOptions, 'currency'>> {\n withoutSymbol?: boolean;\n customSymbol?: string;\n}\n\n/**\n * Formats a numeric price using locale and currency options.\n *\n * @example\n * ```ts\n * formatPrice(1990, 'ru-RU', 'RUB');\n * ```\n */\nexport const formatPrice = (\n price: number,\n locale: string,\n currency?: string,\n { withoutSymbol, customSymbol, ...options }: PriceFormatOptions = {},\n) => {\n const priceFormatter = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n currencyDisplay: 'narrowSymbol',\n ...options,\n });\n\n const zeroPrice = priceFormatter.format(0);\n const currencySymbol = zeroPrice.replace('0', '');\n const rawPrice = priceFormatter.format(price);\n const priceWithoutCurrency = rawPrice.replace(currencySymbol, '');\n\n if (withoutSymbol) {\n return priceWithoutCurrency;\n }\n\n return `${priceWithoutCurrency} ${\n customSymbol ?? (currency === 'RUB' ? 'р' : currencySymbol)\n }`.replace(/\\s{2,}/, ' ');\n};\n"],"mappings":";;;;;;;;;;AAcA,IAAa,eACX,OACA,QACA,UACA,EAAE,eAAe,cAAc,GAAG,YAAgC,EAAE,KACjE;CACH,MAAM,iBAAiB,IAAI,KAAK,aAAa,QAAQ;EACnD,OAAO;EACP;EACA,uBAAuB;EACvB,iBAAiB;EACjB,GAAG;EACJ,CAAC;CAGF,MAAM,iBADY,eAAe,OAAO,EAAE,CACT,QAAQ,KAAK,GAAG;CAEjD,MAAM,uBADW,eAAe,OAAO,MAAM,CACP,QAAQ,gBAAgB,GAAG;AAEjE,KAAI,cACF,QAAO;AAGT,QAAO,GAAG,qBAAqB,GAC7B,iBAAiB,aAAa,QAAQ,MAAM,kBAC3C,QAAQ,UAAU,IAAI"}
1
+ {"version":3,"file":"price.cjs","names":[],"sources":["../src/price.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/price\n *\n * ## Description\n *\n * Locale-aware **money formatting** via `Intl.NumberFormat`, with optional symbol hiding and\n * custom currency symbols for legacy UI. It wraps browser i18n APIs so storefronts and dashboards\n * share one implementation for RUB/EUR/USD-style output without pulling a heavy formatting library.\n *\n * ## Usage\n *\n * ```ts\n * import { formatPrice } from \"yummies/price\";\n * ```\n */\n\nexport interface PriceFormatOptions\n extends Partial<Omit<Intl.NumberFormatOptions, 'currency'>> {\n withoutSymbol?: boolean;\n customSymbol?: string;\n}\n\n/**\n * Formats a numeric price using locale and currency options.\n *\n * @example\n * ```ts\n * formatPrice(1990, 'ru-RU', 'RUB');\n * ```\n */\nexport const formatPrice = (\n price: number,\n locale: string,\n currency?: string,\n { withoutSymbol, customSymbol, ...options }: PriceFormatOptions = {},\n) => {\n const priceFormatter = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n currencyDisplay: 'narrowSymbol',\n ...options,\n });\n\n const zeroPrice = priceFormatter.format(0);\n const currencySymbol = zeroPrice.replace('0', '');\n const rawPrice = priceFormatter.format(price);\n const priceWithoutCurrency = rawPrice.replace(currencySymbol, '');\n\n if (withoutSymbol) {\n return priceWithoutCurrency;\n }\n\n return `${priceWithoutCurrency} ${\n customSymbol ?? (currency === 'RUB' ? 'р' : currencySymbol)\n }`.replace(/\\s{2,}/, ' ');\n};\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,eACX,OACA,QACA,UACA,EAAE,eAAe,cAAc,GAAG,YAAgC,EAAE,KACjE;CACH,MAAM,iBAAiB,IAAI,KAAK,aAAa,QAAQ;EACnD,OAAO;EACP;EACA,uBAAuB;EACvB,iBAAiB;EACjB,GAAG;EACJ,CAAC;CAGF,MAAM,iBADY,eAAe,OAAO,EAAE,CACT,QAAQ,KAAK,GAAG;CAEjD,MAAM,uBADW,eAAe,OAAO,MAAM,CACP,QAAQ,gBAAgB,GAAG;AAEjE,KAAI,cACF,QAAO;AAGT,QAAO,GAAG,qBAAqB,GAC7B,iBAAiB,aAAa,QAAQ,MAAM,kBAC3C,QAAQ,UAAU,IAAI"}
package/price.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ /**
2
+ * ---header-docs-section---
3
+ * # yummies/price
4
+ *
5
+ * ## Description
6
+ *
7
+ * Locale-aware **money formatting** via `Intl.NumberFormat`, with optional symbol hiding and
8
+ * custom currency symbols for legacy UI. It wraps browser i18n APIs so storefronts and dashboards
9
+ * share one implementation for RUB/EUR/USD-style output without pulling a heavy formatting library.
10
+ *
11
+ * ## Usage
12
+ *
13
+ * ```ts
14
+ * import { formatPrice } from "yummies/price";
15
+ * ```
16
+ */
1
17
  interface PriceFormatOptions extends Partial<Omit<Intl.NumberFormatOptions, 'currency'>> {
2
18
  withoutSymbol?: boolean;
3
19
  customSymbol?: string;
package/price.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"price.js","names":[],"sources":["../src/price.ts"],"sourcesContent":["export interface PriceFormatOptions\n extends Partial<Omit<Intl.NumberFormatOptions, 'currency'>> {\n withoutSymbol?: boolean;\n customSymbol?: string;\n}\n\n/**\n * Formats a numeric price using locale and currency options.\n *\n * @example\n * ```ts\n * formatPrice(1990, 'ru-RU', 'RUB');\n * ```\n */\nexport const formatPrice = (\n price: number,\n locale: string,\n currency?: string,\n { withoutSymbol, customSymbol, ...options }: PriceFormatOptions = {},\n) => {\n const priceFormatter = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n currencyDisplay: 'narrowSymbol',\n ...options,\n });\n\n const zeroPrice = priceFormatter.format(0);\n const currencySymbol = zeroPrice.replace('0', '');\n const rawPrice = priceFormatter.format(price);\n const priceWithoutCurrency = rawPrice.replace(currencySymbol, '');\n\n if (withoutSymbol) {\n return priceWithoutCurrency;\n }\n\n return `${priceWithoutCurrency} ${\n customSymbol ?? (currency === 'RUB' ? 'р' : currencySymbol)\n }`.replace(/\\s{2,}/, ' ');\n};\n"],"mappings":";;;;;;;;;AAcA,IAAa,eACX,OACA,QACA,UACA,EAAE,eAAe,cAAc,GAAG,YAAgC,EAAE,KACjE;CACH,MAAM,iBAAiB,IAAI,KAAK,aAAa,QAAQ;EACnD,OAAO;EACP;EACA,uBAAuB;EACvB,iBAAiB;EACjB,GAAG;EACJ,CAAC;CAGF,MAAM,iBADY,eAAe,OAAO,EAAE,CACT,QAAQ,KAAK,GAAG;CAEjD,MAAM,uBADW,eAAe,OAAO,MAAM,CACP,QAAQ,gBAAgB,GAAG;AAEjE,KAAI,cACF,QAAO;AAGT,QAAO,GAAG,qBAAqB,GAC7B,iBAAiB,aAAa,QAAQ,MAAM,kBAC3C,QAAQ,UAAU,IAAI"}
1
+ {"version":3,"file":"price.js","names":[],"sources":["../src/price.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/price\n *\n * ## Description\n *\n * Locale-aware **money formatting** via `Intl.NumberFormat`, with optional symbol hiding and\n * custom currency symbols for legacy UI. It wraps browser i18n APIs so storefronts and dashboards\n * share one implementation for RUB/EUR/USD-style output without pulling a heavy formatting library.\n *\n * ## Usage\n *\n * ```ts\n * import { formatPrice } from \"yummies/price\";\n * ```\n */\n\nexport interface PriceFormatOptions\n extends Partial<Omit<Intl.NumberFormatOptions, 'currency'>> {\n withoutSymbol?: boolean;\n customSymbol?: string;\n}\n\n/**\n * Formats a numeric price using locale and currency options.\n *\n * @example\n * ```ts\n * formatPrice(1990, 'ru-RU', 'RUB');\n * ```\n */\nexport const formatPrice = (\n price: number,\n locale: string,\n currency?: string,\n { withoutSymbol, customSymbol, ...options }: PriceFormatOptions = {},\n) => {\n const priceFormatter = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n currencyDisplay: 'narrowSymbol',\n ...options,\n });\n\n const zeroPrice = priceFormatter.format(0);\n const currencySymbol = zeroPrice.replace('0', '');\n const rawPrice = priceFormatter.format(price);\n const priceWithoutCurrency = rawPrice.replace(currencySymbol, '');\n\n if (withoutSymbol) {\n return priceWithoutCurrency;\n }\n\n return `${priceWithoutCurrency} ${\n customSymbol ?? (currency === 'RUB' ? 'р' : currencySymbol)\n }`.replace(/\\s{2,}/, ' ');\n};\n"],"mappings":";;;;;;;;;AA+BA,IAAa,eACX,OACA,QACA,UACA,EAAE,eAAe,cAAc,GAAG,YAAgC,EAAE,KACjE;CACH,MAAM,iBAAiB,IAAI,KAAK,aAAa,QAAQ;EACnD,OAAO;EACP;EACA,uBAAuB;EACvB,iBAAiB;EACjB,GAAG;EACJ,CAAC;CAGF,MAAM,iBADY,eAAe,OAAO,EAAE,CACT,QAAQ,KAAK,GAAG;CAEjD,MAAM,uBADW,eAAe,OAAO,MAAM,CACP,QAAQ,gBAAgB,GAAG;AAEjE,KAAI,cACF,QAAO;AAGT,QAAO,GAAG,qBAAqB,GAC7B,iBAAiB,aAAa,QAAQ,MAAM,kBAC3C,QAAQ,UAAU,IAAI"}
package/random.cjs CHANGED
@@ -1,6 +1,22 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/random.ts
3
3
  /**
4
+ * ---header-docs-section---
5
+ * # yummies/random
6
+ *
7
+ * ## Description
8
+ *
9
+ * Small RNG helpers for UI demos, games, and sampling: floats, integers, and random choices from
10
+ * arrays. They wrap `Math.random` (not cryptographically secure) so prefer platform `crypto` when
11
+ * generating secrets, tokens, or lottery outcomes.
12
+ *
13
+ * ## Usage
14
+ *
15
+ * ```ts
16
+ * import { getRandomInt, getRandomChoice } from "yummies/random";
17
+ * ```
18
+ */
19
+ /**
4
20
  * Returns a random floating-point number between `min` and `max`.
5
21
  *
6
22
  * @example
package/random.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"random.cjs","names":[],"sources":["../src/random.ts"],"sourcesContent":["/**\n * Returns a random floating-point number between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomFloat(1, 10);\n * ```\n */\nexport const getRandomFloat = <T extends number = number>(\n min = 0,\n max = 1,\n): T => (Math.random() * (max - min) + min) as T;\n\n/**\n * Returns a random integer between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomInt(1, 10);\n * ```\n */\nexport const getRandomInt = <T extends number = number>(min = 0, max = 1): T =>\n min === max ? (min as T) : (Math.round(getRandomFloat(min, max)) as T);\n\n/**\n * Picks a random element from the provided array.\n *\n * @example\n * ```ts\n * const fruit = getRandomChoice(['apple', 'banana', 'orange']);\n * ```\n */\nexport const getRandomChoice = <T>(arr: T[]): T =>\n arr[getRandomInt(0, arr.length - 1)];\n\n/**\n * Creates an array filled with `null` values using a random length.\n *\n * @example\n * ```ts\n * const items = getRandomSizeArray(2, 5);\n * ```\n */\nexport const getRandomSizeArray = (min = 0, max = 10) =>\n Array.from({ length: getRandomInt(min, max) }).fill(null);\n\n/**\n * Returns a uniformly random boolean.\n *\n * @example\n * ```ts\n * const value = getRandomBool();\n * ```\n */\nexport const getRandomBool = () => getRandomInt(0, 1) === 1;\n\n/**\n * Returns `true` more often than `false`.\n *\n * @example\n * ```ts\n * const value = getMajorRandomBool();\n * ```\n */\nexport const getMajorRandomBool = () => {\n return getRandomInt(0, 10) <= 6;\n};\n\n/**\n * Returns `true` less often than `false`.\n *\n * @example\n * ```ts\n * const value = getMinorRandomBool();\n * ```\n */\nexport const getMinorRandomBool = () => {\n return !getMajorRandomBool();\n};\n\n/**\n * Returns `true` with the provided probability from `0` to `1`.\n *\n * @example\n * ```ts\n * const shouldRun = getFrequencyValue(0.25);\n * ```\n */\nexport const getFrequencyValue = (frequency: number) => {\n return Math.random() < frequency;\n};\n"],"mappings":";;;;;;;;;;AAQA,IAAa,kBACX,MAAM,GACN,MAAM,MACC,KAAK,QAAQ,IAAI,MAAM,OAAO;;;;;;;;;AAUvC,IAAa,gBAA2C,MAAM,GAAG,MAAM,MACrE,QAAQ,MAAO,MAAa,KAAK,MAAM,eAAe,KAAK,IAAI,CAAC;;;;;;;;;AAUlE,IAAa,mBAAsB,QACjC,IAAI,aAAa,GAAG,IAAI,SAAS,EAAE;;;;;;;;;AAUrC,IAAa,sBAAsB,MAAM,GAAG,MAAM,OAChD,MAAM,KAAK,EAAE,QAAQ,aAAa,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,KAAK;;;;;;;;;AAU3D,IAAa,sBAAsB,aAAa,GAAG,EAAE,KAAK;;;;;;;;;AAU1D,IAAa,2BAA2B;AACtC,QAAO,aAAa,GAAG,GAAG,IAAI;;;;;;;;;;AAWhC,IAAa,2BAA2B;AACtC,QAAO,CAAC,oBAAoB;;;;;;;;;;AAW9B,IAAa,qBAAqB,cAAsB;AACtD,QAAO,KAAK,QAAQ,GAAG"}
1
+ {"version":3,"file":"random.cjs","names":[],"sources":["../src/random.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/random\n *\n * ## Description\n *\n * Small RNG helpers for UI demos, games, and sampling: floats, integers, and random choices from\n * arrays. They wrap `Math.random` (not cryptographically secure) so prefer platform `crypto` when\n * generating secrets, tokens, or lottery outcomes.\n *\n * ## Usage\n *\n * ```ts\n * import { getRandomInt, getRandomChoice } from \"yummies/random\";\n * ```\n */\n\n/**\n * Returns a random floating-point number between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomFloat(1, 10);\n * ```\n */\nexport const getRandomFloat = <T extends number = number>(\n min = 0,\n max = 1,\n): T => (Math.random() * (max - min) + min) as T;\n\n/**\n * Returns a random integer between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomInt(1, 10);\n * ```\n */\nexport const getRandomInt = <T extends number = number>(min = 0, max = 1): T =>\n min === max ? (min as T) : (Math.round(getRandomFloat(min, max)) as T);\n\n/**\n * Picks a random element from the provided array.\n *\n * @example\n * ```ts\n * const fruit = getRandomChoice(['apple', 'banana', 'orange']);\n * ```\n */\nexport const getRandomChoice = <T>(arr: T[]): T =>\n arr[getRandomInt(0, arr.length - 1)];\n\n/**\n * Creates an array filled with `null` values using a random length.\n *\n * @example\n * ```ts\n * const items = getRandomSizeArray(2, 5);\n * ```\n */\nexport const getRandomSizeArray = (min = 0, max = 10) =>\n Array.from({ length: getRandomInt(min, max) }).fill(null);\n\n/**\n * Returns a uniformly random boolean.\n *\n * @example\n * ```ts\n * const value = getRandomBool();\n * ```\n */\nexport const getRandomBool = () => getRandomInt(0, 1) === 1;\n\n/**\n * Returns `true` more often than `false`.\n *\n * @example\n * ```ts\n * const value = getMajorRandomBool();\n * ```\n */\nexport const getMajorRandomBool = () => {\n return getRandomInt(0, 10) <= 6;\n};\n\n/**\n * Returns `true` less often than `false`.\n *\n * @example\n * ```ts\n * const value = getMinorRandomBool();\n * ```\n */\nexport const getMinorRandomBool = () => {\n return !getMajorRandomBool();\n};\n\n/**\n * Returns `true` with the provided probability from `0` to `1`.\n *\n * @example\n * ```ts\n * const shouldRun = getFrequencyValue(0.25);\n * ```\n */\nexport const getFrequencyValue = (frequency: number) => {\n return Math.random() < frequency;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,kBACX,MAAM,GACN,MAAM,MACC,KAAK,QAAQ,IAAI,MAAM,OAAO;;;;;;;;;AAUvC,IAAa,gBAA2C,MAAM,GAAG,MAAM,MACrE,QAAQ,MAAO,MAAa,KAAK,MAAM,eAAe,KAAK,IAAI,CAAC;;;;;;;;;AAUlE,IAAa,mBAAsB,QACjC,IAAI,aAAa,GAAG,IAAI,SAAS,EAAE;;;;;;;;;AAUrC,IAAa,sBAAsB,MAAM,GAAG,MAAM,OAChD,MAAM,KAAK,EAAE,QAAQ,aAAa,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,KAAK;;;;;;;;;AAU3D,IAAa,sBAAsB,aAAa,GAAG,EAAE,KAAK;;;;;;;;;AAU1D,IAAa,2BAA2B;AACtC,QAAO,aAAa,GAAG,GAAG,IAAI;;;;;;;;;;AAWhC,IAAa,2BAA2B;AACtC,QAAO,CAAC,oBAAoB;;;;;;;;;;AAW9B,IAAa,qBAAqB,cAAsB;AACtD,QAAO,KAAK,QAAQ,GAAG"}
package/random.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ /**
2
+ * ---header-docs-section---
3
+ * # yummies/random
4
+ *
5
+ * ## Description
6
+ *
7
+ * Small RNG helpers for UI demos, games, and sampling: floats, integers, and random choices from
8
+ * arrays. They wrap `Math.random` (not cryptographically secure) so prefer platform `crypto` when
9
+ * generating secrets, tokens, or lottery outcomes.
10
+ *
11
+ * ## Usage
12
+ *
13
+ * ```ts
14
+ * import { getRandomInt, getRandomChoice } from "yummies/random";
15
+ * ```
16
+ */
1
17
  /**
2
18
  * Returns a random floating-point number between `min` and `max`.
3
19
  *
package/random.js CHANGED
@@ -1,5 +1,21 @@
1
1
  //#region src/random.ts
2
2
  /**
3
+ * ---header-docs-section---
4
+ * # yummies/random
5
+ *
6
+ * ## Description
7
+ *
8
+ * Small RNG helpers for UI demos, games, and sampling: floats, integers, and random choices from
9
+ * arrays. They wrap `Math.random` (not cryptographically secure) so prefer platform `crypto` when
10
+ * generating secrets, tokens, or lottery outcomes.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { getRandomInt, getRandomChoice } from "yummies/random";
16
+ * ```
17
+ */
18
+ /**
3
19
  * Returns a random floating-point number between `min` and `max`.
4
20
  *
5
21
  * @example
package/random.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"random.js","names":[],"sources":["../src/random.ts"],"sourcesContent":["/**\n * Returns a random floating-point number between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomFloat(1, 10);\n * ```\n */\nexport const getRandomFloat = <T extends number = number>(\n min = 0,\n max = 1,\n): T => (Math.random() * (max - min) + min) as T;\n\n/**\n * Returns a random integer between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomInt(1, 10);\n * ```\n */\nexport const getRandomInt = <T extends number = number>(min = 0, max = 1): T =>\n min === max ? (min as T) : (Math.round(getRandomFloat(min, max)) as T);\n\n/**\n * Picks a random element from the provided array.\n *\n * @example\n * ```ts\n * const fruit = getRandomChoice(['apple', 'banana', 'orange']);\n * ```\n */\nexport const getRandomChoice = <T>(arr: T[]): T =>\n arr[getRandomInt(0, arr.length - 1)];\n\n/**\n * Creates an array filled with `null` values using a random length.\n *\n * @example\n * ```ts\n * const items = getRandomSizeArray(2, 5);\n * ```\n */\nexport const getRandomSizeArray = (min = 0, max = 10) =>\n Array.from({ length: getRandomInt(min, max) }).fill(null);\n\n/**\n * Returns a uniformly random boolean.\n *\n * @example\n * ```ts\n * const value = getRandomBool();\n * ```\n */\nexport const getRandomBool = () => getRandomInt(0, 1) === 1;\n\n/**\n * Returns `true` more often than `false`.\n *\n * @example\n * ```ts\n * const value = getMajorRandomBool();\n * ```\n */\nexport const getMajorRandomBool = () => {\n return getRandomInt(0, 10) <= 6;\n};\n\n/**\n * Returns `true` less often than `false`.\n *\n * @example\n * ```ts\n * const value = getMinorRandomBool();\n * ```\n */\nexport const getMinorRandomBool = () => {\n return !getMajorRandomBool();\n};\n\n/**\n * Returns `true` with the provided probability from `0` to `1`.\n *\n * @example\n * ```ts\n * const shouldRun = getFrequencyValue(0.25);\n * ```\n */\nexport const getFrequencyValue = (frequency: number) => {\n return Math.random() < frequency;\n};\n"],"mappings":";;;;;;;;;AAQA,IAAa,kBACX,MAAM,GACN,MAAM,MACC,KAAK,QAAQ,IAAI,MAAM,OAAO;;;;;;;;;AAUvC,IAAa,gBAA2C,MAAM,GAAG,MAAM,MACrE,QAAQ,MAAO,MAAa,KAAK,MAAM,eAAe,KAAK,IAAI,CAAC;;;;;;;;;AAUlE,IAAa,mBAAsB,QACjC,IAAI,aAAa,GAAG,IAAI,SAAS,EAAE;;;;;;;;;AAUrC,IAAa,sBAAsB,MAAM,GAAG,MAAM,OAChD,MAAM,KAAK,EAAE,QAAQ,aAAa,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,KAAK;;;;;;;;;AAU3D,IAAa,sBAAsB,aAAa,GAAG,EAAE,KAAK;;;;;;;;;AAU1D,IAAa,2BAA2B;AACtC,QAAO,aAAa,GAAG,GAAG,IAAI;;;;;;;;;;AAWhC,IAAa,2BAA2B;AACtC,QAAO,CAAC,oBAAoB;;;;;;;;;;AAW9B,IAAa,qBAAqB,cAAsB;AACtD,QAAO,KAAK,QAAQ,GAAG"}
1
+ {"version":3,"file":"random.js","names":[],"sources":["../src/random.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/random\n *\n * ## Description\n *\n * Small RNG helpers for UI demos, games, and sampling: floats, integers, and random choices from\n * arrays. They wrap `Math.random` (not cryptographically secure) so prefer platform `crypto` when\n * generating secrets, tokens, or lottery outcomes.\n *\n * ## Usage\n *\n * ```ts\n * import { getRandomInt, getRandomChoice } from \"yummies/random\";\n * ```\n */\n\n/**\n * Returns a random floating-point number between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomFloat(1, 10);\n * ```\n */\nexport const getRandomFloat = <T extends number = number>(\n min = 0,\n max = 1,\n): T => (Math.random() * (max - min) + min) as T;\n\n/**\n * Returns a random integer between `min` and `max`.\n *\n * @example\n * ```ts\n * const value = getRandomInt(1, 10);\n * ```\n */\nexport const getRandomInt = <T extends number = number>(min = 0, max = 1): T =>\n min === max ? (min as T) : (Math.round(getRandomFloat(min, max)) as T);\n\n/**\n * Picks a random element from the provided array.\n *\n * @example\n * ```ts\n * const fruit = getRandomChoice(['apple', 'banana', 'orange']);\n * ```\n */\nexport const getRandomChoice = <T>(arr: T[]): T =>\n arr[getRandomInt(0, arr.length - 1)];\n\n/**\n * Creates an array filled with `null` values using a random length.\n *\n * @example\n * ```ts\n * const items = getRandomSizeArray(2, 5);\n * ```\n */\nexport const getRandomSizeArray = (min = 0, max = 10) =>\n Array.from({ length: getRandomInt(min, max) }).fill(null);\n\n/**\n * Returns a uniformly random boolean.\n *\n * @example\n * ```ts\n * const value = getRandomBool();\n * ```\n */\nexport const getRandomBool = () => getRandomInt(0, 1) === 1;\n\n/**\n * Returns `true` more often than `false`.\n *\n * @example\n * ```ts\n * const value = getMajorRandomBool();\n * ```\n */\nexport const getMajorRandomBool = () => {\n return getRandomInt(0, 10) <= 6;\n};\n\n/**\n * Returns `true` less often than `false`.\n *\n * @example\n * ```ts\n * const value = getMinorRandomBool();\n * ```\n */\nexport const getMinorRandomBool = () => {\n return !getMajorRandomBool();\n};\n\n/**\n * Returns `true` with the provided probability from `0` to `1`.\n *\n * @example\n * ```ts\n * const shouldRun = getFrequencyValue(0.25);\n * ```\n */\nexport const getFrequencyValue = (frequency: number) => {\n return Math.random() < frequency;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,kBACX,MAAM,GACN,MAAM,MACC,KAAK,QAAQ,IAAI,MAAM,OAAO;;;;;;;;;AAUvC,IAAa,gBAA2C,MAAM,GAAG,MAAM,MACrE,QAAQ,MAAO,MAAa,KAAK,MAAM,eAAe,KAAK,IAAI,CAAC;;;;;;;;;AAUlE,IAAa,mBAAsB,QACjC,IAAI,aAAa,GAAG,IAAI,SAAS,EAAE;;;;;;;;;AAUrC,IAAa,sBAAsB,MAAM,GAAG,MAAM,OAChD,MAAM,KAAK,EAAE,QAAQ,aAAa,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,KAAK;;;;;;;;;AAU3D,IAAa,sBAAsB,aAAa,GAAG,EAAE,KAAK;;;;;;;;;AAU1D,IAAa,2BAA2B;AACtC,QAAO,aAAa,GAAG,GAAG,IAAI;;;;;;;;;;AAWhC,IAAa,2BAA2B;AACtC,QAAO,CAAC,oBAAoB;;;;;;;;;;AAW9B,IAAa,qBAAqB,cAAsB;AACtD,QAAO,KAAK,QAAQ,GAAG"}
package/sound.cjs CHANGED
@@ -1,6 +1,22 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/sound.ts
3
3
  /**
4
+ * ---header-docs-section---
5
+ * # yummies/sound
6
+ *
7
+ * ## Description
8
+ *
9
+ * One-shot HTMLAudio playback for short UI sounds (clicks, success chimes) with volume control.
10
+ * The helper creates a temporary `Audio` element, awaits `play()`, then drops references so callers
11
+ * do not leak nodes. Autoplay policies may still block sound until a user gesture on some browsers.
12
+ *
13
+ * ## Usage
14
+ *
15
+ * ```ts
16
+ * import { playSound } from "yummies/sound";
17
+ * ```
18
+ */
19
+ /**
4
20
  * Plays a sound from a file.
5
21
  */
6
22
  var playSound = async (file, { volume = 1 } = {}) => {
package/sound.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sound.cjs","names":[],"sources":["../src/sound.ts"],"sourcesContent":["/**\n * Plays a sound from a file.\n */\nexport const playSound = async (\n file: string,\n { volume = 1 }: { volume?: number } = {},\n) => {\n let audio = new Audio(file);\n audio.volume = volume;\n audio.muted = !volume;\n await audio.play();\n audio.remove();\n // @ts-expect-error\n audio = null;\n};\n"],"mappings":";;;;;AAGA,IAAa,YAAY,OACvB,MACA,EAAE,SAAS,MAA2B,EAAE,KACrC;CACH,IAAI,QAAQ,IAAI,MAAM,KAAK;AAC3B,OAAM,SAAS;AACf,OAAM,QAAQ,CAAC;AACf,OAAM,MAAM,MAAM;AAClB,OAAM,QAAQ;AAEd,SAAQ"}
1
+ {"version":3,"file":"sound.cjs","names":[],"sources":["../src/sound.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/sound\n *\n * ## Description\n *\n * One-shot HTMLAudio playback for short UI sounds (clicks, success chimes) with volume control.\n * The helper creates a temporary `Audio` element, awaits `play()`, then drops references so callers\n * do not leak nodes. Autoplay policies may still block sound until a user gesture on some browsers.\n *\n * ## Usage\n *\n * ```ts\n * import { playSound } from \"yummies/sound\";\n * ```\n */\n\n/**\n * Plays a sound from a file.\n */\nexport const playSound = async (\n file: string,\n { volume = 1 }: { volume?: number } = {},\n) => {\n let audio = new Audio(file);\n audio.volume = volume;\n audio.muted = !volume;\n await audio.play();\n audio.remove();\n // @ts-expect-error\n audio = null;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,YAAY,OACvB,MACA,EAAE,SAAS,MAA2B,EAAE,KACrC;CACH,IAAI,QAAQ,IAAI,MAAM,KAAK;AAC3B,OAAM,SAAS;AACf,OAAM,QAAQ,CAAC;AACf,OAAM,MAAM,MAAM;AAClB,OAAM,QAAQ;AAEd,SAAQ"}
package/sound.d.ts CHANGED
@@ -1,3 +1,19 @@
1
+ /**
2
+ * ---header-docs-section---
3
+ * # yummies/sound
4
+ *
5
+ * ## Description
6
+ *
7
+ * One-shot HTMLAudio playback for short UI sounds (clicks, success chimes) with volume control.
8
+ * The helper creates a temporary `Audio` element, awaits `play()`, then drops references so callers
9
+ * do not leak nodes. Autoplay policies may still block sound until a user gesture on some browsers.
10
+ *
11
+ * ## Usage
12
+ *
13
+ * ```ts
14
+ * import { playSound } from "yummies/sound";
15
+ * ```
16
+ */
1
17
  /**
2
18
  * Plays a sound from a file.
3
19
  */
package/sound.js CHANGED
@@ -1,5 +1,21 @@
1
1
  //#region src/sound.ts
2
2
  /**
3
+ * ---header-docs-section---
4
+ * # yummies/sound
5
+ *
6
+ * ## Description
7
+ *
8
+ * One-shot HTMLAudio playback for short UI sounds (clicks, success chimes) with volume control.
9
+ * The helper creates a temporary `Audio` element, awaits `play()`, then drops references so callers
10
+ * do not leak nodes. Autoplay policies may still block sound until a user gesture on some browsers.
11
+ *
12
+ * ## Usage
13
+ *
14
+ * ```ts
15
+ * import { playSound } from "yummies/sound";
16
+ * ```
17
+ */
18
+ /**
3
19
  * Plays a sound from a file.
4
20
  */
5
21
  var playSound = async (file, { volume = 1 } = {}) => {
package/sound.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sound.js","names":[],"sources":["../src/sound.ts"],"sourcesContent":["/**\n * Plays a sound from a file.\n */\nexport const playSound = async (\n file: string,\n { volume = 1 }: { volume?: number } = {},\n) => {\n let audio = new Audio(file);\n audio.volume = volume;\n audio.muted = !volume;\n await audio.play();\n audio.remove();\n // @ts-expect-error\n audio = null;\n};\n"],"mappings":";;;;AAGA,IAAa,YAAY,OACvB,MACA,EAAE,SAAS,MAA2B,EAAE,KACrC;CACH,IAAI,QAAQ,IAAI,MAAM,KAAK;AAC3B,OAAM,SAAS;AACf,OAAM,QAAQ,CAAC;AACf,OAAM,MAAM,MAAM;AAClB,OAAM,QAAQ;AAEd,SAAQ"}
1
+ {"version":3,"file":"sound.js","names":[],"sources":["../src/sound.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/sound\n *\n * ## Description\n *\n * One-shot HTMLAudio playback for short UI sounds (clicks, success chimes) with volume control.\n * The helper creates a temporary `Audio` element, awaits `play()`, then drops references so callers\n * do not leak nodes. Autoplay policies may still block sound until a user gesture on some browsers.\n *\n * ## Usage\n *\n * ```ts\n * import { playSound } from \"yummies/sound\";\n * ```\n */\n\n/**\n * Plays a sound from a file.\n */\nexport const playSound = async (\n file: string,\n { volume = 1 }: { volume?: number } = {},\n) => {\n let audio = new Audio(file);\n audio.volume = volume;\n audio.muted = !volume;\n await audio.play();\n audio.remove();\n // @ts-expect-error\n audio = null;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,YAAY,OACvB,MACA,EAAE,SAAS,MAA2B,EAAE,KACrC;CACH,IAAI,QAAQ,IAAI,MAAM,KAAK;AAC3B,OAAM,SAAS;AACf,OAAM,QAAQ,CAAC;AACf,OAAM,MAAM,MAAM;AAClB,OAAM,QAAQ;AAEd,SAAQ"}