Skip to main content

stacks-utils

Use when needing general utility functions in Stacks - deep merge, debounce/throttle, color output, byte formatting, markdown tables, YAML parsing, Pipeline class, ResizeObserver, Macroable, project initialization, indentation detection, or the comprehensive utility toolkit. Covers @stacksjs/utils.

Informações da origem

Repositório
stacksjs/stacks
Última atividade na origem
29 de agosto de 2026 às 17:05
Idioma detectado do SKILL.md
inglês
Estrelas
631
Forks
20

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
stacks-utils
description
Use when needing general utility functions in Stacks - deep merge, debounce/throttle, color output, byte formatting, markdown tables, YAML parsing, Pipeline class, ResizeObserver, Macroable, project initialization, indentation detection, or the comprehensive utility toolkit. Covers @stacksjs/utils.
license
MIT
compatibility
Bun >= 1.3.0, TypeScript
allowed-tools
Read Edit Write Bash Grep Glob
# Stacks Utilities Umbrella package providing utility functions plus re-exports from specialized packages. ## Key Paths - Core package: `storage/framework/core/utils/src/` - Package: `@stacksjs/utils` ## Architecture The `index.ts` re-exports from these local modules: - `clean.ts` — project cleanup (`cleanProject()`) - `config.ts` — config builder re-exports from `@stacksjs/config` - `equal.ts` — deep equality - `export-size.ts` — re-exports from `size.ts` - `find.ts` — find Stacks projects on filesystem - `git.ts` — git status check - `hash.ts` — path hashing for cloud deploy - `helpers.ts` — project helpers (env, YAML, version, npm scripts, etc.) - `macroable.ts` — dynamic method registration on classes - `versions.ts` — semver comparison via `Bun.semver` - `merge.ts` — deep object merge (defu replacement) - `detect.ts` — indentation and newline detection - `debounce.ts` — debounce, throttle, delay - `bytes.ts` — byte formatting and parsing - `colors.ts` — ANSI terminal color output - `markdown.ts` — markdown table generation - `size.ts` — file/export size calculation - `observer.ts` — ResizeObserver polyfill - `pipeline.ts` — Pipeline class for data transformation chains Also re-exports from `@stacksjs/browser`: ```typescript export * as browserUtils from '@stacksjs/browser' export { clamp, notNullish, retry, useOnline } from '@stacksjs/browser' ``` ## Deep Merge (`merge.ts`) Replacement for `defu`. Arrays are concatenated, objects are recursively merged, special objects (Date, RegExp, Error, Promise, Map, Set, WeakMap, WeakSet, ArrayBuffer views) are NOT deeply merged. ```typescript import { merge, mergeDefaults, createMerger, defu } from '@stacksjs/utils' merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 } merge({ a: [1] }, { a: [2] }) // { a: [1, 2] } -- arrays concatenated merge({ a: { x: 1 } }, { a: { y: 2 } }) // { a: { x: 1, y: 2 } } -- objects merged mergeDefaults(obj, defaults1, defaults2) // merge defaults first, obj wins const merger = createMerger(defaults) // reusable merger function defu(obj, defaults1, defaults2) // alias for mergeDefaults ``` Key behavior: `undefined` values in source objects are skipped. Later arguments take precedence in `merge()`, but the first argument takes precedence in `mergeDefaults()`/`defu()`. ## Debounce & Throttle (`debounce.ts`) ```typescript interface DebounceOptions { leading?: boolean // default: false trailing?: boolean // default: true } const debouncedFn = debounce(fn, 300, { leading: false, trailing: true }) debouncedFn.cancel() // cancel pending invocation debouncedFn.flush() // immediately invoke pending, returns result const throttledFn = throttle(fn, 100) throttledFn.cancel() // cancel pending invocation await delay(1000) // sleep for 1 second (returns Promise<void>) ``` Note: unlike some implementations, this debounce does NOT support `maxWait`. The throttle uses `Date.now()` for timing, not setTimeout stacking. ## Color Output (`colors.ts`) ANSI terminal color library. Auto-detects support via `process.env.NO_COLOR`, `process.env.FORCE_COLOR`, and `process.stdout.isTTY`. ### Text Colors ```typescript black('text'), red('text'), green('text'), yellow('text') blue('text'), magenta('text'), cyan('text'), white('text') gray('text'), grey('text') // grey is alias for gray ``` ### Bright Text Colors ```typescript lightRed('text'), lightGreen('text'), lightYellow('text'), lightBlue('text') lightMagenta('text'), lightCyan('text'), lightGray('text'), lightGrey('text') ``` ### Background Colors ```typescript bgBlack('text'), bgRed('text'), bgGreen('text'), bgYellow('text') bgBlue('text'), bgMagenta('text'), bgCyan('text'), bgWhite('text') ``` ### Bright Background Colors ```typescript bgLightRed('text'), bgLightGreen('text'), bgLightYellow('text'), bgLightBlue('text') bgLightMagenta('text'), bgLightCyan('text') ``` ### Text Formatting ```typescript bold('text'), dim('text'), italic('text'), underline('text') inverse('text'), hidden('text'), strikethrough('text'), reset('text') ``` ### Utilities ```typescript stripColors(coloredText) // remove all ANSI escape codes supportsColor() // boolean -- is color output supported? ``` All color functions accept `string | number` and return `string`. When colors are unsupported, they return `String(text)` unchanged. ## Byte Formatting (`bytes.ts`) ```typescript interface BytesOptions { precision?: number // default: 1 binary?: boolean // use KiB/MiB/GiB (default: false, uses KB/MB/GB) space?: boolean // space between number and unit (default: true) locale?: string // number formatting locale (default: 'en-US') minimumFractionDigits?: number // default: 0 maximumFractionDigits?: number // default: precision } formatBytes(1024) // '1 KB' formatBytes(1024, { binary: true }) // '1 KiB' formatBytes(1234567, { precision: 2 }) // '1.23 MB' formatBytes(-1024) // '-1 KB' formatBytes(0.5) // '0.5 B' parseBytes('1 KB') // 1000 parseBytes('1 KiB') // 1024 parseBytes('1.5 MB') // 1500000 compareBytes('1 MB', '1 GB') // negative number (a < b) compareBytes(1024, '1 KB') // 24 (a > b) // Aliases prettyBytes(1024) // alias for formatBytes readableSize(1024) // alias for formatBytes ``` Units: B, KB, MB, GB, TB, PB, EB, ZB, YB (decimal) or B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB (binary). ## Export Size Calculation (`size.ts`) ```typescript interface ExportSize { name: string // relative path size: number // bytes readable: string // human-readable } interface PackageExportsSizeResult { totalSize: number totalReadable: string exports: ExportSize[] // sorted by size descending } await getFileSize('/path/to/file') // number (bytes), returns 0 on error const result = await getExportsSize('./dist') // PackageExportsSizeResult estimateGzipSize(size) // Math.floor(size * 0.3) estimateBrotliSize(size) // Math.floor(size * 0.25) formatExportSizes(result) // formatted multi-line string with table ``` `getExportsSize` scans a directory for `.js`, `.mjs`, `.cjs` files and calculates their sizes. ## Pipeline (`pipeline.ts`) Laravel-inspired pipeline for chaining data transformations. ```typescript type PipeFunction<T> = (data: T, next: (data: T) => T) => T interface PipeClass<T> { handle: PipeFunction<T> } // Array-based chaining const result = Pipeline.send(data) .through([transform1, transform2, transform3]) .via('process') // method name on pipe classes (default: 'handle') .then((data) => data) // final transformation // Fluent pipe chaining const result2 = Pipeline.send(data) .pipe(fn1) .pipe(fn2) .thenReturn() // returns data as-is after pipeline // Pipes can be functions or objects with a handle/via method Pipeline.send('hello') .through([ (data, next) => next(data.toUpperCase()), (data, next) => next(data + '!'), ]) .then(data => data) // 'HELLO!' ``` Internally uses `reduceRight` so pipes execute in order (first pipe wraps outermost). ## Markdown Tables (`markdown.ts`) ```typescript interface MarkdownTableOptions { align?: Array<'l' | 'c' | 'r' | 'left' | 'center' | 'right' | null> padding?: boolean // default: true delimiter?: string // default: '|' delimiterStart?: boolean // default: true delimiterEnd?: boolean // default: true alignDelimiter?: string // default: '-' } markdownTable([ ['Name', 'Age', 'City'], ['Alice', '30', 'NYC'], ['Bob', '25', 'LA'] ]) // | Name | Age | City | // | ----- | --- | ---- | // | Alice | 30 | NYC | // | Bob | 25 | LA | markdownTable([['Left', 'Center', 'Right'], ['a', 'b', 'c']], { align: ['l', 'c', 'r'] }) // Uses :--- for left, :---: for center, ---: for right markdownTableFromObjects([ { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 } ]) // Auto-generates header from object keys ``` Cell values can be `string | number | boolean | null | undefined` -- all are converted to strings. ## YAML (`helpers.ts`) Uses `Bun.YAML` natively: ```typescript parseYaml(yamlString) // Bun.YAML.parse(content) loadYaml(content) // alias for parseYaml dumpYaml(object) // Bun.YAML.stringify(content), falls back to JSON.stringify ``` ## Macroable (`macroable.ts`) Laravel-inspired dynamic method registration on classes. ```typescript import { Macroable, createMacroable, macroable } from '@stacksjs/utils' // Option 1: Extend Macroable class MyClass extends Macroable {} MyClass.macro('greet', function() { return 'Hello!' }) const instance = new MyClass() ;(instance as any).greet() // 'Hello!' MyClass.hasMacro('greet') // true MyClass.getMacros() // ['greet'] MyClass.flushMacros() // remove all macros // Mixin multiple methods from an object MyClass.mixin({ hello() { return 'hi' }, bye() { return 'bye' } }) // replace parameter (default: true for mixin, false for macro) MyClass.macro('greet', newFn, true) // replace existing // Option 2: Create macroable from existing class const MacroClass = createMacroable(BaseClass) // Option 3: Add macroable functionality to existing class const Enhanced = macroable(ExistingClass) Enhanced.macro('newMethod', fn) ``` Static methods: `macro(name, fn, replace?)`, `mixin(obj, replace?)`, `hasMacro(name)`, `flushMacros()`, `getMacros()`. ## ResizeObserver (`observer.ts`) ```typescript isResizeObserverSupported() // boolean const RO = getResizeObserver() // native or polyfill class const cleanup = createResizeObserver(callback, element) const cleanup2 = createResizeObserver(callback, [el1, el2]) // multiple elements cleanup() // disconnect observer const stop = observeElementSize(element, (entry) => { console.log(entry.contentRect.width, entry.contentRect.height) }) stop() // stop observing ``` The polyfill uses `requestAnimationFrame` (or `setTimeout` fallback) to poll element sizes via `getBoundingClientRect()`. ## Deep Equality (`equal.ts`) ```typescript isDeepEqual(obj1, obj2) // deep structural equality isDeepEqual([1, 2], [1, 2]) // true isDeepEqual({ a: 1 }, { a: 1 }) // true isDeepEqual(NaN, NaN) // true (uses Object.is) ``` Compares arrays element-by-element, objects key-by-key, primitives with `Object.is`. ## Version Comparison (`versions.ts`) Uses `Bun.semver` natively: ```typescript const semver: typeof Bun.semver = Bun.semver isVersionGreaterThan('2.0.0', '1.0.0') // true isVersionLessThan('1.0.0', '2.0.0') // true
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub