@sqlrooms/utils 0.28.0-rc.0 → 0.28.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.
package/README.md CHANGED
@@ -1,98 +1,76 @@
1
- A collection of utility functions and helpers for SQLRooms applications. This package provides common utilities for string manipulation, file handling, color management, formatting, and more.
2
-
3
- ## Features
4
-
5
- - 🔠 **String Utilities**: Functions for string manipulation and formatting
6
- - 📁 **File Path Handling**: Tools for working with file paths and extensions
7
- - 🎨 **Color Utilities**: Color conversion and manipulation functions
8
- - 📊 **Formatting**: Data formatting for display purposes
9
- - 🔄 **XHR Helpers**: Utilities for working with XMLHttpRequests
10
- - 🧰 **General Helpers**: Common helper functions for everyday tasks
1
+ Shared utility functions used across SQLRooms packages and apps.
11
2
 
12
3
  ## Installation
13
4
 
14
5
  ```bash
15
6
  npm install @sqlrooms/utils
16
- # or
17
- yarn add @sqlrooms/utils
18
7
  ```
19
8
 
20
- ## Basic Usage
21
-
22
- ### String Utilities
23
-
24
- ```tsx
25
- import {truncate, capitalize, slugify} from '@sqlrooms/utils';
26
-
27
- // Truncate long text
28
- const shortText = truncate(
29
- 'This is a very long text that needs to be shortened',
30
- 20,
31
- );
32
- console.log(shortText); // 'This is a very long...'
33
-
34
- // Capitalize text
35
- const capitalized = capitalize('hello world');
36
- console.log(capitalized); // 'Hello world'
37
-
38
- // Create a URL-friendly slug
39
- const slug = slugify('Hello World! This is a test');
40
- console.log(slug); // 'hello-world-this-is-a-test'
9
+ ## String and formatting helpers
10
+
11
+ ```ts
12
+ import {
13
+ capitalize,
14
+ camelCaseToTitle,
15
+ truncate,
16
+ formatBytes,
17
+ formatNumber,
18
+ formatDate,
19
+ formatDateTime,
20
+ formatTimeRelative,
21
+ } from '@sqlrooms/utils';
22
+
23
+ capitalize('hello'); // "Hello"
24
+ camelCaseToTitle('tableRowCount'); // "Table Row Count"
25
+ truncate('This is a long sentence', 10); // "This is..."
26
+
27
+ formatBytes(1048576); // "1 MB"
28
+ formatNumber(1234567.89); // "1,234,568"
29
+ formatDate(new Date()); // "2026-02-23"
30
+ formatDateTime(new Date()); // "Mon 2026-02-23 02:15 PM"
31
+ formatTimeRelative(Date.now() - 60_000); // "a minute ago"
41
32
  ```
42
33
 
43
- ### File Path Utilities
34
+ ## File/table name helpers
44
35
 
45
- ```tsx
46
- import {getFileExtension, joinPaths, normalizePath} from '@sqlrooms/utils';
36
+ ```ts
37
+ import {
38
+ convertToValidColumnOrTableName,
39
+ convertToUniqueColumnOrTableName,
40
+ generateUniqueName,
41
+ splitFilePath,
42
+ generateUniquePath,
43
+ } from '@sqlrooms/utils';
47
44
 
48
- // Get file extension
49
- const ext = getFileExtension('document.pdf');
50
- console.log(ext); // 'pdf'
45
+ convertToValidColumnOrTableName('My File.csv'); // "My_File"
46
+ convertToUniqueColumnOrTableName('sales.csv', ['sales']); // "sales_1"
47
+ generateUniqueName('query', ['query', 'query_1']); // "query_2"
51
48
 
52
- // Join path segments
53
- const fullPath = joinPaths('/base/path', 'subfolder', 'file.txt');
54
- console.log(fullPath); // '/base/path/subfolder/file.txt'
49
+ splitFilePath('folder/data.parquet');
50
+ // { dir: "folder", name: "data", ext: "parquet", filename: "data.parquet" }
55
51
 
56
- // Normalize a path
57
- const normalized = normalizePath('/path//to/../folder/./file.txt');
58
- console.log(normalized); // '/path/folder/file.txt'
52
+ generateUniquePath('results.csv', ['results.csv']); // "results_1.csv"
59
53
  ```
60
54
 
61
- ### JSON Utilities
55
+ ## Network and JSON helpers
62
56
 
63
- ```tsx
64
- import {safeJsonParse} from '@sqlrooms/utils';
57
+ ```ts
58
+ import {safeJsonParse, downloadFile, uploadFile, postData} from '@sqlrooms/utils';
65
59
 
66
- // Safely parse JSON without throwing exceptions
67
- const result = safeJsonParse('{"name": "John", "age": 30}');
68
- console.log(result); // { name: 'John', age: 30 }
60
+ const parsed = safeJsonParse('{"ok": true}'); // { ok: true }
61
+ const invalid = safeJsonParse('{'); // undefined
69
62
 
70
- // Handle invalid JSON gracefully
71
- const invalid = safeJsonParse('{"name": "John", age: 30}');
72
- console.log(invalid); // undefined
63
+ // downloadFile / uploadFile / postData are Promise-based XHR helpers
73
64
  ```
74
65
 
75
- ### Formatting Utilities
76
-
77
- ```tsx
78
- import {formatBytes, formatNumber, formatDate} from '@sqlrooms/utils';
79
-
80
- // Format file size
81
- console.log(formatBytes(1024)); // '1 KB'
82
- console.log(formatBytes(1048576)); // '1 MB'
83
-
84
- // Format numbers
85
- console.log(formatNumber(1234567.89)); // '1,234,567.89'
86
-
87
- // Format dates
88
- console.log(formatDate(new Date(), 'yyyy-MM-dd')); // '2023-04-15'
89
- ```
90
-
91
- ## Advanced Features
92
-
93
- - **Type Safety**: All utilities are fully typed with TypeScript
94
- - **Browser Compatibility**: Works in all modern browsers
95
- - **Tree-Shakable**: Import only what you need to minimize bundle size
96
- - **No Dependencies**: Zero external runtime dependencies
97
-
98
- For more information, visit the SQLRooms documentation.
66
+ ## Other useful exports
67
+
68
+ - `memoizeOnce`
69
+ - `opacifyHex`
70
+ - `formatCount`, `formatCountShort`, `shorten`
71
+ - decimal helpers:
72
+ - `isNegativeDecimal`
73
+ - `negateDecimal`
74
+ - `toDecimalString`
75
+ - `toDecimalNumber`
76
+ - `fromDecimalString`
@@ -1 +1 @@
1
- {"version":3,"file":"memoization.d.ts","sourceRoot":"","sources":["../src/memoization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,EAAE,OAAO,EACnE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAC9B,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAsB7B"}
1
+ {"version":3,"file":"memoization.d.ts","sourceRoot":"","sources":["../src/memoization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,EAAE,OAAO,EACnE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAC9B,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAkB7B"}
@@ -36,9 +36,7 @@ export function memoizeOnce(fn) {
36
36
  return lastResult;
37
37
  }
38
38
  // Call the function with the correct context and cache the result
39
- lastResult = fn.apply(this,
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- args);
39
+ lastResult = fn.apply(this, args);
42
40
  lastArgs = args;
43
41
  hasResult = true;
44
42
  return lastResult;
@@ -1 +1 @@
1
- {"version":3,"file":"memoization.js","sourceRoot":"","sources":["../src/memoization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,WAAW,CACzB,EAA+B;IAE/B,IAAI,QAA2B,CAAC;IAChC,IAAI,UAAmB,CAAC;IACxB,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,OAAO,UAAyB,GAAG,IAAW;QAC5C,iEAAiE;QACjE,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;YACvD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,kEAAkE;QAClE,UAAU,GAAG,EAAE,CAAC,KAAK,CACnB,IAAI;QACJ,8DAA8D;QAC9D,IAAwB,CACzB,CAAC;QACF,QAAQ,GAAG,IAAI,CAAC;QAChB,SAAS,GAAG,IAAI,CAAC;QAEjB,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAA+B,CAAI,EAAE,CAAI;IACzD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,CAAC","sourcesContent":["/**\n * Creates a memoized version of a function that caches only the last result.\n * The cache is invalidated when any of the arguments change.\n *\n * This is useful for expensive operations that are likely to be called\n * multiple times with the same arguments, like database queries or API calls.\n *\n * @param fn - The function to memoize\n * @returns A memoized version of the function\n *\n * @example\n * ```ts\n * const expensiveQuery = async (userId: string, limit: number) => {\n * return await database.query(`SELECT * FROM users WHERE id = ? LIMIT ?`, [userId, limit]);\n * };\n *\n * const memoizedQuery = memoizeOnce(expensiveQuery);\n *\n * // First call executes the function\n * const result1 = await memoizedQuery(\"123\", 10);\n *\n * // Second call with same arguments returns cached result\n * const result2 = await memoizedQuery(\"123\", 10); // Uses cache\n *\n * // Call with different arguments invalidates cache and executes function\n * const result3 = await memoizedQuery(\"456\", 10); // Executes function\n * ```\n */\nexport function memoizeOnce<TArgs extends readonly unknown[], TReturn>(\n fn: (...args: TArgs) => TReturn,\n): (...args: TArgs) => TReturn {\n let lastArgs: TArgs | undefined;\n let lastResult: TReturn;\n let hasResult = false;\n\n return function (this: unknown, ...args: TArgs): TReturn {\n // Check if we have a cached result and arguments haven't changed\n if (hasResult && lastArgs && argsEqual(lastArgs, args)) {\n return lastResult;\n }\n\n // Call the function with the correct context and cache the result\n lastResult = fn.apply(\n this,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n args as unknown as any[],\n );\n lastArgs = args;\n hasResult = true;\n\n return lastResult;\n };\n}\n\n/**\n * Shallow comparison of two arrays to check if all elements are equal\n */\nfunction argsEqual<T extends readonly unknown[]>(a: T, b: T): boolean {\n if (a.length !== b.length) return false;\n return a.every((val, index) => val === b[index]);\n}\n"]}
1
+ {"version":3,"file":"memoization.js","sourceRoot":"","sources":["../src/memoization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,WAAW,CACzB,EAA+B;IAE/B,IAAI,QAA2B,CAAC;IAChC,IAAI,UAAmB,CAAC;IACxB,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,OAAO,UAAyB,GAAG,IAAW;QAC5C,iEAAiE;QACjE,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;YACvD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,kEAAkE;QAClE,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,IAAwB,CAAC,CAAC;QACtD,QAAQ,GAAG,IAAI,CAAC;QAChB,SAAS,GAAG,IAAI,CAAC;QAEjB,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAA+B,CAAI,EAAE,CAAI;IACzD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,CAAC","sourcesContent":["/**\n * Creates a memoized version of a function that caches only the last result.\n * The cache is invalidated when any of the arguments change.\n *\n * This is useful for expensive operations that are likely to be called\n * multiple times with the same arguments, like database queries or API calls.\n *\n * @param fn - The function to memoize\n * @returns A memoized version of the function\n *\n * @example\n * ```ts\n * const expensiveQuery = async (userId: string, limit: number) => {\n * return await database.query(`SELECT * FROM users WHERE id = ? LIMIT ?`, [userId, limit]);\n * };\n *\n * const memoizedQuery = memoizeOnce(expensiveQuery);\n *\n * // First call executes the function\n * const result1 = await memoizedQuery(\"123\", 10);\n *\n * // Second call with same arguments returns cached result\n * const result2 = await memoizedQuery(\"123\", 10); // Uses cache\n *\n * // Call with different arguments invalidates cache and executes function\n * const result3 = await memoizedQuery(\"456\", 10); // Executes function\n * ```\n */\nexport function memoizeOnce<TArgs extends readonly unknown[], TReturn>(\n fn: (...args: TArgs) => TReturn,\n): (...args: TArgs) => TReturn {\n let lastArgs: TArgs | undefined;\n let lastResult: TReturn;\n let hasResult = false;\n\n return function (this: unknown, ...args: TArgs): TReturn {\n // Check if we have a cached result and arguments haven't changed\n if (hasResult && lastArgs && argsEqual(lastArgs, args)) {\n return lastResult;\n }\n\n // Call the function with the correct context and cache the result\n lastResult = fn.apply(this, args as unknown as any[]);\n lastArgs = args;\n hasResult = true;\n\n return lastResult;\n };\n}\n\n/**\n * Shallow comparison of two arrays to check if all elements are equal\n */\nfunction argsEqual<T extends readonly unknown[]>(a: T, b: T): boolean {\n if (a.length !== b.length) return false;\n return a.every((val, index) => val === b[index]);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/utils",
3
- "version": "0.28.0-rc.0",
3
+ "version": "0.28.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.js",
@@ -43,5 +43,5 @@
43
43
  "react": ">=18",
44
44
  "react-dom": ">=18"
45
45
  },
46
- "gitHead": "87a478edbff690e04c38cc717db8e11e844565c8"
46
+ "gitHead": "dcac54f8adf77240e293c93d224a0ce9fd8142a9"
47
47
  }