@edgeandnode/eds-utils 1.0.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/bigIntToNumber.d.ts +17 -0
  4. package/dist/bigIntToNumber.d.ts.map +1 -0
  5. package/dist/bigIntToNumber.js +25 -0
  6. package/dist/bigIntToNumber.js.map +1 -0
  7. package/dist/camelToKebab.d.ts +3 -0
  8. package/dist/camelToKebab.d.ts.map +1 -0
  9. package/dist/camelToKebab.js +15 -0
  10. package/dist/camelToKebab.js.map +1 -0
  11. package/dist/constants.d.ts +3 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +3 -0
  14. package/dist/constants.js.map +1 -0
  15. package/dist/createIdenticon.d.ts +2 -0
  16. package/dist/createIdenticon.d.ts.map +1 -0
  17. package/dist/createIdenticon.js +75 -0
  18. package/dist/createIdenticon.js.map +1 -0
  19. package/dist/formatAddress.d.ts +14 -0
  20. package/dist/formatAddress.d.ts.map +1 -0
  21. package/dist/formatAddress.js +28 -0
  22. package/dist/formatAddress.js.map +1 -0
  23. package/dist/formatBigInt.d.ts +23 -0
  24. package/dist/formatBigInt.d.ts.map +1 -0
  25. package/dist/formatBigInt.js +38 -0
  26. package/dist/formatBigInt.js.map +1 -0
  27. package/dist/getKey.d.ts +14 -0
  28. package/dist/getKey.d.ts.map +1 -0
  29. package/dist/getKey.js +36 -0
  30. package/dist/getKey.js.map +1 -0
  31. package/dist/index.d.ts +14 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +14 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/loremIpsum.d.ts +11 -0
  36. package/dist/loremIpsum.d.ts.map +1 -0
  37. package/dist/loremIpsum.js +136 -0
  38. package/dist/loremIpsum.js.map +1 -0
  39. package/dist/numberToBigInt.d.ts +18 -0
  40. package/dist/numberToBigInt.d.ts.map +1 -0
  41. package/dist/numberToBigInt.js +27 -0
  42. package/dist/numberToBigInt.js.map +1 -0
  43. package/dist/parseBigInt.d.ts +25 -0
  44. package/dist/parseBigInt.d.ts.map +1 -0
  45. package/dist/parseBigInt.js +35 -0
  46. package/dist/parseBigInt.js.map +1 -0
  47. package/dist/parseNumber.d.ts +17 -0
  48. package/dist/parseNumber.d.ts.map +1 -0
  49. package/dist/parseNumber.js +18 -0
  50. package/dist/parseNumber.js.map +1 -0
  51. package/dist/sliceWrap.d.ts +3 -0
  52. package/dist/sliceWrap.d.ts.map +1 -0
  53. package/dist/sliceWrap.js +11 -0
  54. package/dist/sliceWrap.js.map +1 -0
  55. package/dist/types.d.ts +6 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +2 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +37 -0
  60. package/src/bigIntToNumber.ts +34 -0
  61. package/src/camelToKebab.ts +16 -0
  62. package/src/constants.ts +2 -0
  63. package/src/createIdenticon.ts +84 -0
  64. package/src/formatAddress.ts +33 -0
  65. package/src/formatBigInt.ts +60 -0
  66. package/src/getKey.ts +37 -0
  67. package/src/index.ts +13 -0
  68. package/src/loremIpsum.ts +143 -0
  69. package/src/numberToBigInt.ts +38 -0
  70. package/src/parseBigInt.ts +51 -0
  71. package/src/parseNumber.ts +24 -0
  72. package/src/sliceWrap.ts +9 -0
  73. package/src/types.ts +4 -0
package/src/getKey.ts ADDED
@@ -0,0 +1,37 @@
1
+ const refMap = new WeakMap<object, string>()
2
+ let refCounter = 0
3
+
4
+ /**
5
+ * Generates a stable, unique string key for any JS value.
6
+ *
7
+ * - null / undefined => 'null' / 'undefined'
8
+ * - string / number / boolean => `${type}:${value}` (e.g. 'string:hello', 'number:42',
9
+ * 'boolean:false')
10
+ * - registered symbols (`Symbol.for('foo')`) => 'symbol:foo'
11
+ * - objects / functions / non-registered symbols => one-time ID (e.g. 'ref:1', 'ref:2', etc.)
12
+ *
13
+ * @param value - Any JavaScript value.
14
+ * @returns A string that uniquely and consistently identifies the value.
15
+ */
16
+ export function getKey(value: unknown): string {
17
+ if (value === null) return 'null'
18
+ if (value === undefined) return 'undefined'
19
+
20
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
21
+ return `${typeof value}:${value}`
22
+ }
23
+
24
+ if (typeof value === 'symbol') {
25
+ const registryKey = Symbol.keyFor(value)
26
+ if (registryKey !== undefined) {
27
+ return `symbol:${registryKey}`
28
+ }
29
+ }
30
+
31
+ let id = refMap.get(value)
32
+ if (!id) {
33
+ id = `ref:${++refCounter}`
34
+ refMap.set(value, id)
35
+ }
36
+ return id
37
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ export * from './constants.ts'
2
+ export * from './types.ts'
3
+ export { bigIntToNumber, type BigIntToNumberOptions } from './bigIntToNumber.ts'
4
+ export { camelToKebab } from './camelToKebab.ts'
5
+ export { createIdenticon } from './createIdenticon.ts'
6
+ export { formatAddress } from './formatAddress.ts'
7
+ export { formatBigInt, type BigIntFormatOptions } from './formatBigInt.ts'
8
+ export { getKey } from './getKey.ts'
9
+ export { loremIpsum } from './loremIpsum.ts'
10
+ export { numberToBigInt, type NumberToBigIntOptions } from './numberToBigInt.ts'
11
+ export { parseBigInt, type ParseBigIntOptions } from './parseBigInt.ts'
12
+ export { parseNumber, type ParseNumberOptions } from './parseNumber.ts'
13
+ export { sliceWrap } from './sliceWrap.ts'
@@ -0,0 +1,143 @@
1
+ import { sliceWrap } from './sliceWrap.ts'
2
+
3
+ /**
4
+ * Generates lorem ipsum text.
5
+ *
6
+ * @param {number} [count=4] - The number of words, sentences, or paragraphs to generate. Default is
7
+ * `4`
8
+ * @param {'words' | 'sentences' | 'paragraphs'} [units='sentences'] - The units to generate.
9
+ * Default is `'sentences'`
10
+ * @returns {string} The generated text.
11
+ */
12
+ export function loremIpsum(
13
+ count: number = 4,
14
+ units: 'words' | 'sentences' | 'paragraphs' = 'sentences',
15
+ ): string {
16
+ switch (units) {
17
+ case 'words':
18
+ return wordsToSentence(sliceWrap(WORDS, 0, count))
19
+ case 'sentences':
20
+ return sliceWrap(SENTENCES, 0, count)
21
+ .map((sentence) => wordsToSentence(sentence.words))
22
+ .join(' ')
23
+ case 'paragraphs':
24
+ return sliceWrap(PARAGRAPHS, 0, count)
25
+ .map((paragraph) =>
26
+ paragraph.sentences.map((sentence) => wordsToSentence(sentence.words)).join(' '),
27
+ )
28
+ .join('\n')
29
+ }
30
+ }
31
+
32
+ function wordsToSentence(words: string[]) {
33
+ let sentence = ''
34
+ for (const word of words) {
35
+ if (sentence.length > 0) sentence += ' '
36
+ sentence += word
37
+ }
38
+ if (sentence.endsWith(',')) {
39
+ sentence = sentence.slice(0, -1)
40
+ }
41
+ if (sentence.length > 0 && !sentence.endsWith('.')) {
42
+ sentence += '.'
43
+ }
44
+ return sentence
45
+ }
46
+
47
+ const LOREM_IPSUM = {
48
+ paragraphs: [
49
+ {
50
+ sentences: [
51
+ {
52
+ words: [
53
+ 'Lorem',
54
+ 'ipsum',
55
+ 'dolor',
56
+ 'sit',
57
+ 'amet,',
58
+ 'consectetur',
59
+ 'adipiscing',
60
+ 'elit,',
61
+ 'sed',
62
+ 'do',
63
+ 'eiusmod',
64
+ 'tempor',
65
+ 'incididunt',
66
+ 'ut',
67
+ 'labore',
68
+ 'et',
69
+ 'dolore',
70
+ 'magna',
71
+ 'aliqua.',
72
+ ],
73
+ },
74
+ {
75
+ words: [
76
+ 'Ut',
77
+ 'enim',
78
+ 'ad',
79
+ 'minim',
80
+ 'veniam,',
81
+ 'quis',
82
+ 'nostrud',
83
+ 'exercitation',
84
+ 'ullamco',
85
+ 'laboris',
86
+ 'nisi',
87
+ 'ut',
88
+ 'aliquip',
89
+ 'ex',
90
+ 'ea',
91
+ 'commodo',
92
+ 'consequat.',
93
+ ],
94
+ },
95
+ {
96
+ words: [
97
+ 'Duis',
98
+ 'aute',
99
+ 'irure',
100
+ 'dolor',
101
+ 'in',
102
+ 'reprehenderit',
103
+ 'in',
104
+ 'voluptate',
105
+ 'velit',
106
+ 'esse',
107
+ 'cillum',
108
+ 'dolore',
109
+ 'eu',
110
+ 'fugiat',
111
+ 'nulla',
112
+ 'pariatur.',
113
+ ],
114
+ },
115
+ {
116
+ words: [
117
+ 'Excepteur',
118
+ 'sint',
119
+ 'occaecat',
120
+ 'cupidatat',
121
+ 'non',
122
+ 'proident,',
123
+ 'sunt',
124
+ 'in',
125
+ 'culpa',
126
+ 'qui',
127
+ 'officia',
128
+ 'deserunt',
129
+ 'mollit',
130
+ 'anim',
131
+ 'id',
132
+ 'est',
133
+ 'laborum.',
134
+ ],
135
+ },
136
+ ],
137
+ },
138
+ ],
139
+ }
140
+
141
+ const PARAGRAPHS = LOREM_IPSUM.paragraphs
142
+ const SENTENCES = PARAGRAPHS.flatMap((paragraph) => paragraph.sentences)
143
+ const WORDS = SENTENCES.flatMap((sentence) => sentence.words)
@@ -0,0 +1,38 @@
1
+ import { parseBigInt } from './parseBigInt.ts'
2
+
3
+ export interface NumberToBigIntOptions {
4
+ /**
5
+ * The number of digits starting from the right of the returned bigint to consider as decimal
6
+ * places.
7
+ *
8
+ * @default 18n
9
+ */
10
+ precision?: bigint | undefined
11
+ }
12
+
13
+ /**
14
+ * Converts a number to a bigint. Decimals to the right of `precision` are truncated.
15
+ *
16
+ * @param value - The number to convert to a bigint.
17
+ * @param options - Conversion options.
18
+ * @returns The bigint representation of `value`
19
+ */
20
+ export function numberToBigInt(value: number, options?: NumberToBigIntOptions): bigint {
21
+ const { precision = 18n } = options ?? {}
22
+ if (precision < 0n) {
23
+ throw new Error(`[numberToBigInt] \`precision\` must be positive, got ${precision}`)
24
+ }
25
+ // If `value` has decimals and `precision` is at least 1, parse it as a string
26
+ if (value % 1 !== 0 && precision >= 1n) {
27
+ const parsedValue = parseBigInt(String(value), { precision })
28
+ if (parsedValue === null) {
29
+ throw new Error(
30
+ `[numberToBigInt] Failed to parse ${value} as a bigint with precision ${precision}`,
31
+ )
32
+ }
33
+ return parsedValue
34
+ } else {
35
+ const precisionFactor = 10n ** precision
36
+ return BigInt(Math.trunc(value)) * precisionFactor
37
+ }
38
+ }
@@ -0,0 +1,51 @@
1
+ export interface ParseBigIntOptions {
2
+ /**
3
+ * The number of digits starting from the right of the returned bigint to consider as decimal
4
+ * places.
5
+ *
6
+ * @default 18n
7
+ */
8
+ precision?: bigint | undefined
9
+ /**
10
+ * If true, requires exact match (no commas, no extra whitespace)
11
+ *
12
+ * @default false
13
+ */
14
+ strict?: boolean | undefined
15
+ }
16
+
17
+ /**
18
+ * Like `parseNumber()`, but returns a bigint instead of a number. Decimals to the right of
19
+ * `precision` are truncated.
20
+ *
21
+ * @param value - The string to parse as a bigint.
22
+ * @param options - Parsing options.
23
+ * @returns The bigint representation of `value`, or `null` if we failed to parse it.
24
+ */
25
+ export function parseBigInt(value: string, options?: ParseBigIntOptions) {
26
+ const { precision = 18n, strict = false } = options ?? {}
27
+ if (precision < 0n) {
28
+ throw new Error(`[parseBigInt] \`precision\` must be positive, got ${precision}`)
29
+ }
30
+
31
+ const originalValue = value
32
+ const cleanedValue = value.replace(/,/g, '').trim()
33
+
34
+ if (strict && cleanedValue !== originalValue) return null
35
+ if (cleanedValue === '' || cleanedValue === '-' || cleanedValue === '.' || cleanedValue === '-.')
36
+ return null
37
+
38
+ const [integerPart, decimalPart = '', somethingAfterDecimalPart] = cleanedValue.split('.')
39
+ if (integerPart!.trim() !== integerPart) return null
40
+ if (decimalPart.trim() !== decimalPart) return null
41
+ if (somethingAfterDecimalPart !== undefined) return null
42
+
43
+ try {
44
+ const precisionNumber = Number(precision)
45
+ return BigInt(
46
+ `${integerPart}${decimalPart.slice(0, precisionNumber).padEnd(precisionNumber, '0')}`,
47
+ )
48
+ } catch {
49
+ return null
50
+ }
51
+ }
@@ -0,0 +1,24 @@
1
+ export interface ParseNumberOptions {
2
+ /**
3
+ * If true, requires exact match (no commas, no extra whitespace)
4
+ *
5
+ * @default false
6
+ */
7
+ strict?: boolean | undefined
8
+ }
9
+
10
+ /**
11
+ * Parses a string value into a number, with optional strict mode.
12
+ *
13
+ * @param value - The string value to parse.
14
+ * @param options - Parsing options.
15
+ * @returns The parsed number, or null if parsing fails.
16
+ */
17
+ export function parseNumber(value: string, options?: ParseNumberOptions) {
18
+ const { strict = false } = options ?? {}
19
+ const cleanedValue = value.replace(/,/g, '').trim()
20
+ if (cleanedValue === '' || (cleanedValue !== value && strict)) return null
21
+ const number = Number(cleanedValue)
22
+ if (!Number.isFinite(number) || (String(number) !== cleanedValue && strict)) return null
23
+ return number
24
+ }
@@ -0,0 +1,9 @@
1
+ /** Same as `array.slice(start, end)`, but wraps around the end of the array. */
2
+ export function sliceWrap<T>(array: T[], start: number, end: number) {
3
+ if (array.length === 0) return []
4
+ const result: typeof array = []
5
+ for (let i = start; i < end; i++) {
6
+ result.push(array[i % array.length]!)
7
+ }
8
+ return result
9
+ }
package/src/types.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { SetNonNullable, SetRequired } from 'type-fest'
2
+
3
+ export type DeepRecord<Value> = { [key: string]: Value | DeepRecord<Value> }
4
+ export type SetRequiredNonNullable<T, K extends keyof T> = SetRequired<SetNonNullable<T, K>, K>