@bessemer/cornerstone 0.5.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 (66) hide show
  1. package/jest.config.js +3 -0
  2. package/package.json +39 -0
  3. package/src/array.ts +142 -0
  4. package/src/async.ts +114 -0
  5. package/src/cache.ts +236 -0
  6. package/src/combinable.ts +40 -0
  7. package/src/comparator.ts +78 -0
  8. package/src/content.ts +138 -0
  9. package/src/context.ts +6 -0
  10. package/src/crypto.ts +11 -0
  11. package/src/date.ts +18 -0
  12. package/src/duration.ts +57 -0
  13. package/src/either.ts +29 -0
  14. package/src/entry.ts +21 -0
  15. package/src/equalitor.ts +12 -0
  16. package/src/error-event.ts +126 -0
  17. package/src/error.ts +16 -0
  18. package/src/expression/array-expression.ts +29 -0
  19. package/src/expression/expression-evaluator.ts +34 -0
  20. package/src/expression/expression.ts +188 -0
  21. package/src/expression/internal.ts +34 -0
  22. package/src/expression/numeric-expression.ts +182 -0
  23. package/src/expression/string-expression.ts +38 -0
  24. package/src/expression.ts +48 -0
  25. package/src/function.ts +3 -0
  26. package/src/glob.ts +19 -0
  27. package/src/global-variable.ts +40 -0
  28. package/src/hash.ts +28 -0
  29. package/src/hex-code.ts +6 -0
  30. package/src/index.ts +82 -0
  31. package/src/lazy.ts +11 -0
  32. package/src/logger.ts +144 -0
  33. package/src/math.ts +132 -0
  34. package/src/misc.ts +22 -0
  35. package/src/object.ts +236 -0
  36. package/src/patch.ts +128 -0
  37. package/src/precondition.ts +25 -0
  38. package/src/promise.ts +16 -0
  39. package/src/property.ts +29 -0
  40. package/src/reference.ts +68 -0
  41. package/src/resource.ts +32 -0
  42. package/src/result.ts +66 -0
  43. package/src/retry.ts +70 -0
  44. package/src/rich-text.ts +24 -0
  45. package/src/set.ts +46 -0
  46. package/src/signature.ts +20 -0
  47. package/src/store.ts +91 -0
  48. package/src/string.ts +173 -0
  49. package/src/tag.ts +68 -0
  50. package/src/types.ts +21 -0
  51. package/src/ulid.ts +28 -0
  52. package/src/unit.ts +4 -0
  53. package/src/uri.ts +321 -0
  54. package/src/url.ts +155 -0
  55. package/src/uuid.ts +37 -0
  56. package/src/zod.ts +24 -0
  57. package/test/comparator.test.ts +1 -0
  58. package/test/expression.test.ts +12 -0
  59. package/test/object.test.ts +104 -0
  60. package/test/patch.test.ts +170 -0
  61. package/test/set.test.ts +20 -0
  62. package/test/string.test.ts +22 -0
  63. package/test/uri.test.ts +111 -0
  64. package/test/url.test.ts +174 -0
  65. package/tsconfig.build.json +13 -0
  66. package/tsup.config.ts +4 -0
@@ -0,0 +1,188 @@
1
+ import { ExpressionEvaluator } from '@bessemer/cornerstone/expression/expression-evaluator'
2
+ import {
3
+ ArrayExpressions,
4
+ EvaluateExpression,
5
+ Expression,
6
+ ExpressionContext,
7
+ ExpressionDefinition,
8
+ ExpressionReference,
9
+ ExpressionVariable,
10
+ NumericExpressions,
11
+ ParameterizedVariable,
12
+ StringExpressions,
13
+ } from '@bessemer/cornerstone/expression'
14
+ import { Arrays, Objects, Preconditions, Signatures } from '@bessemer/cornerstone'
15
+ import { Signable } from '@bessemer/cornerstone/signature'
16
+ import { defineExpression } from '@bessemer/cornerstone/expression/internal'
17
+ import { UnknownRecord } from 'type-fest'
18
+
19
+ export const evaluate = <T>(expression: Expression<T>, context: ExpressionContext): T => {
20
+ return new ExpressionEvaluator(DEFAULT_EXPRESSION_DEFINITIONS).evaluate(expression, context)
21
+ }
22
+
23
+ export const evaluateDefault = <T>(expression: Expression<T>): T => {
24
+ return evaluate(expression, defaultContext())
25
+ }
26
+
27
+ export const evaluator = (context: ExpressionContext): EvaluateExpression => {
28
+ return (it) => evaluate(it, context)
29
+ }
30
+
31
+ export const defaultEvaluator = (): EvaluateExpression => {
32
+ return evaluator(defaultContext())
33
+ }
34
+
35
+ export const defaultContext = (): ExpressionContext => {
36
+ return { variables: {} }
37
+ }
38
+
39
+ export const dereference = <ReturnType, ArgumentType extends Array<unknown>>(
40
+ reference: ExpressionReference<ReturnType, ArgumentType>,
41
+ ...args: ArgumentType
42
+ ): Expression<ReturnType> => {
43
+ return new ExpressionEvaluator(DEFAULT_EXPRESSION_DEFINITIONS).dereference(reference, ...args)
44
+ }
45
+
46
+ export const parameterizedVariable = <ValueType, ParameterType extends Array<Signable>>(
47
+ name: string
48
+ ): ParameterizedVariable<ValueType, ParameterType> => {
49
+ return {
50
+ apply(...parameters: ParameterType): ExpressionVariable<ValueType> {
51
+ const parameterString = parameters.map(Signatures.sign).join('.')
52
+ return variable(`${name}.${parameterString}`)
53
+ },
54
+ }
55
+ }
56
+
57
+ export const buildVariable = <T>(variable: ExpressionVariable<T>, value: T): UnknownRecord => {
58
+ return { [variable.name]: value }
59
+ }
60
+
61
+ export const reference = <ReturnType, ArgumentType extends Array<unknown>, ExpressionType extends Expression<ReturnType>>(
62
+ expressionDefinition: ExpressionDefinition<ReturnType, ArgumentType, ExpressionType>
63
+ ): ExpressionReference<ReturnType, ArgumentType> => {
64
+ return { expressionKey: expressionDefinition.expressionKey }
65
+ }
66
+
67
+ export const ValueExpression = defineExpression({
68
+ expressionKey: 'Value',
69
+ builder: (value: unknown) => {
70
+ return { value }
71
+ },
72
+ resolver: ({ value }, evaluate, context) => {
73
+ return value
74
+ },
75
+ })
76
+
77
+ export const value = <T>(value: T): Expression<T> => ValueExpression.builder(value) as Expression<T>
78
+
79
+ export const VariableExpression = defineExpression({
80
+ expressionKey: 'Variable',
81
+ builder: (name: string) => {
82
+ return { name }
83
+ },
84
+ resolver: ({ name }, evaluate, context) => {
85
+ const value = context.variables[name]
86
+ Preconditions.isPresent(value)
87
+ return value
88
+ },
89
+ })
90
+
91
+ export const variable = <T>(name: string): ExpressionVariable<T> => VariableExpression.builder(name) as ExpressionVariable<T>
92
+
93
+ export const NotExpression = defineExpression({
94
+ expressionKey: 'Not',
95
+ builder: (value: Expression<boolean>) => {
96
+ return { value }
97
+ },
98
+ resolver: (expression, evaluate) => {
99
+ return !evaluate(expression.value)
100
+ },
101
+ })
102
+
103
+ export const not = NotExpression.builder
104
+
105
+ export const AndExpression = defineExpression({
106
+ expressionKey: 'And',
107
+ builder: (operands: Array<Expression<boolean>>) => {
108
+ return { operands }
109
+ },
110
+ resolver: (expression, evaluate) => {
111
+ const values = expression.operands.map((it) => evaluate(it))
112
+ const falseValue = values.find((it) => !it)
113
+ return Objects.isNil(falseValue)
114
+ },
115
+ })
116
+
117
+ export const and = AndExpression.builder
118
+
119
+ export const OrExpression = defineExpression({
120
+ expressionKey: 'Or',
121
+ builder: (operands: Array<Expression<boolean>>) => {
122
+ return { operands }
123
+ },
124
+ resolver: (expression, evaluate) => {
125
+ const values = expression.operands.map((it) => evaluate(it))
126
+ const trueValue = values.find((it) => it)
127
+ return Objects.isPresent(trueValue)
128
+ },
129
+ })
130
+
131
+ export const or = OrExpression.builder
132
+
133
+ export const EqualsExpression = defineExpression({
134
+ expressionKey: 'Equals',
135
+ builder: (operands: Array<Expression<Signable>>) => {
136
+ return { operands }
137
+ },
138
+ resolver: (expression, evaluate) => {
139
+ const values = expression.operands.map((it) => evaluate(it)).map(Signatures.sign)
140
+
141
+ if (values.length === 0) {
142
+ return true
143
+ }
144
+
145
+ const first = values[0]
146
+ return values.every((val) => val === first)
147
+ },
148
+ })
149
+
150
+ export const equals = EqualsExpression.builder
151
+
152
+ export const ContainsExpression = defineExpression({
153
+ expressionKey: 'Contains',
154
+ builder: (collection: Expression<Array<Signable>>, operands: Array<Expression<Signable>>) => {
155
+ return { collection, operands }
156
+ },
157
+ resolver: (expression, evaluate) => {
158
+ const collection = evaluate(expression.collection)
159
+ const values = expression.operands.map((it) => evaluate(it))
160
+ return Arrays.containsAll(collection, values)
161
+ },
162
+ })
163
+
164
+ export const contains = ContainsExpression.builder
165
+
166
+ const DEFAULT_EXPRESSION_DEFINITIONS: Array<ExpressionDefinition<unknown, Array<any>, Expression<any>>> = [
167
+ ValueExpression,
168
+ VariableExpression,
169
+ AndExpression,
170
+ OrExpression,
171
+ ContainsExpression,
172
+ EqualsExpression,
173
+ NumericExpressions.SumExpression,
174
+ NumericExpressions.MultiplyExpression,
175
+ NumericExpressions.GreaterThanExpression,
176
+ NumericExpressions.LessThanExpression,
177
+ NumericExpressions.FloorExpression,
178
+ NumericExpressions.CeilingExpression,
179
+ NumericExpressions.BoundsExpression,
180
+ NumericExpressions.RoundExpression,
181
+ NumericExpressions.MaxExpression,
182
+ NumericExpressions.MinExpression,
183
+ StringExpressions.ConcatenateExpression,
184
+ StringExpressions.SubstringExpression,
185
+ StringExpressions.UppercaseExpression,
186
+ ArrayExpressions.ConcatenateExpression,
187
+ ArrayExpressions.FirstExpression,
188
+ ]
@@ -0,0 +1,34 @@
1
+ import { EvaluateExpression, Expression, ExpressionContext, ExpressionDefinition, ExpressionKey, IExpression } from '@bessemer/cornerstone/expression'
2
+ import { Objects } from '@bessemer/cornerstone'
3
+ import { UnknownRecord } from 'type-fest'
4
+
5
+ export const defineExpression = <ReturnType, ArgumentType extends Array<unknown>, PayloadType extends UnknownRecord>(options: {
6
+ expressionKey: ExpressionKey<ReturnType, ArgumentType>
7
+ builder: (...parameters: ArgumentType) => PayloadType
8
+ resolver: (expression: PayloadType, evaluate: EvaluateExpression, context: ExpressionContext) => ReturnType
9
+ }): ExpressionDefinition<ReturnType, ArgumentType, Expression<ReturnType> & PayloadType> => {
10
+ return {
11
+ expressionKey: options.expressionKey,
12
+ builder: (...parameters) => {
13
+ return { expressionKey: options.expressionKey, ...options.builder(...parameters) }
14
+ },
15
+ resolver: (expression, evaluate, context) => {
16
+ return options.resolver(expression as any, evaluate, context)
17
+ },
18
+ }
19
+ }
20
+
21
+ export const isType = <ReturnValue, ArgumentType extends Array<any>, ExpressionType extends Expression<ReturnValue>>(
22
+ expression: Expression<ReturnValue>,
23
+ expressionDefinition: ExpressionDefinition<ReturnValue, ArgumentType, ExpressionType>
24
+ ): expression is ReturnType<typeof expressionDefinition['builder']> => {
25
+ if (!isExpression(expression)) {
26
+ return false
27
+ }
28
+
29
+ return expression.expressionKey === expressionDefinition.expressionKey
30
+ }
31
+
32
+ export const isExpression = <T>(expression: Expression<any>): expression is IExpression<T> => {
33
+ return Objects.isObject(expression) && 'expressionKey' in expression
34
+ }
@@ -0,0 +1,182 @@
1
+ import { defineExpression, isType } from '@bessemer/cornerstone/expression/internal'
2
+ import { Expression } from '@bessemer/cornerstone/expression'
3
+ import { Maths, Objects } from '@bessemer/cornerstone'
4
+ import { RoundingMode } from '@bessemer/cornerstone/math'
5
+
6
+ export const SumExpression = defineExpression({
7
+ expressionKey: 'Numeric.Sum',
8
+ builder: (initialOperands: Array<Expression<number>>) => {
9
+ const operands: Array<Expression<number>> = initialOperands.flatMap((it) => {
10
+ if (isType(it, SumExpression)) {
11
+ return it.operands
12
+ } else {
13
+ return [it]
14
+ }
15
+ })
16
+
17
+ return { operands }
18
+ },
19
+ resolver: ({ operands }, evaluate) => {
20
+ const values = operands.map((it) => evaluate(it))
21
+ return values.reduce((x, y) => x + y, 0)
22
+ },
23
+ })
24
+
25
+ export const sum = SumExpression.builder
26
+
27
+ export const MultiplyExpression = defineExpression({
28
+ expressionKey: 'Numeric.Multiply',
29
+ builder: (initialOperands: Array<Expression<number>>) => {
30
+ const operands: Array<Expression<number>> = initialOperands.flatMap((it) => {
31
+ if (isType(it, MultiplyExpression)) {
32
+ return it.operands
33
+ } else {
34
+ return [it]
35
+ }
36
+ })
37
+
38
+ return { operands }
39
+ },
40
+ resolver: ({ operands }, evaluate) => {
41
+ const values = operands.map((it) => evaluate(it))
42
+ return values.reduce((x, y) => x * y, 1)
43
+ },
44
+ })
45
+
46
+ export const multiply = MultiplyExpression.builder
47
+
48
+ export const LessThanExpression = defineExpression({
49
+ expressionKey: 'Numeric.LessThan',
50
+ builder: (left: Expression<number>, right: Expression<number>) => {
51
+ return { left, right }
52
+ },
53
+ resolver: ({ left, right }, evaluate) => {
54
+ return evaluate(left) < evaluate(right)
55
+ },
56
+ })
57
+
58
+ export const lessThan = LessThanExpression.builder
59
+
60
+ export const GreaterThanExpression = defineExpression({
61
+ expressionKey: 'Numeric.GreaterThan',
62
+ builder: (left: Expression<number>, right: Expression<number>) => {
63
+ return { left, right }
64
+ },
65
+ resolver: ({ left, right }, evaluate) => {
66
+ return evaluate(left) > evaluate(right)
67
+ },
68
+ })
69
+
70
+ export const greaterThan = GreaterThanExpression.builder
71
+
72
+ export const BoundsExpression = defineExpression({
73
+ expressionKey: 'Numeric.Bounds',
74
+ builder: (value: Expression<number>, minimumThreshold: Expression<number> | null, maximumThreshold: Expression<number> | null) => {
75
+ return { value, minimumThreshold, maximumThreshold }
76
+ },
77
+ resolver: (expression, evaluate) => {
78
+ let value = evaluate(expression.value)
79
+ const minimumThreshold = Objects.isPresent(expression.minimumThreshold) ? evaluate(expression.minimumThreshold) : null
80
+ const maximumThreshold = Objects.isPresent(expression.maximumThreshold) ? evaluate(expression.maximumThreshold) : null
81
+ if (Objects.isPresent(minimumThreshold) && value < minimumThreshold) {
82
+ value = minimumThreshold
83
+ }
84
+ if (Objects.isPresent(maximumThreshold) && value > maximumThreshold) {
85
+ value = maximumThreshold
86
+ }
87
+
88
+ return value
89
+ },
90
+ })
91
+
92
+ export const bounds = BoundsExpression.builder
93
+
94
+ export const FloorExpression = defineExpression({
95
+ expressionKey: 'Numeric.Floor',
96
+ builder: (value: Expression<number>, minimumThreshold: Expression<number> | null) => {
97
+ return { value, minimumThreshold }
98
+ },
99
+ resolver: (expression, evaluate) => {
100
+ let value = evaluate(expression.value)
101
+ const minimumThreshold = Objects.isPresent(expression.minimumThreshold) ? evaluate(expression.minimumThreshold) : null
102
+ if (Objects.isPresent(minimumThreshold) && value < minimumThreshold) {
103
+ value = minimumThreshold
104
+ }
105
+
106
+ return value
107
+ },
108
+ })
109
+
110
+ export const floor = FloorExpression.builder
111
+
112
+ export const CeilingExpression = defineExpression({
113
+ expressionKey: 'Numeric.Ceiling',
114
+ builder: (value: Expression<number>, maximumThreshold: Expression<number> | null) => {
115
+ return { value, maximumThreshold }
116
+ },
117
+ resolver: (expression, evaluate) => {
118
+ let value = evaluate(expression.value)
119
+ const maximumThreshold = Objects.isPresent(expression.maximumThreshold) ? evaluate(expression.maximumThreshold) : null
120
+ if (Objects.isPresent(maximumThreshold) && value > maximumThreshold) {
121
+ value = maximumThreshold
122
+ }
123
+
124
+ return value
125
+ },
126
+ })
127
+
128
+ export const ceiling = CeilingExpression.builder
129
+
130
+ export const RoundExpression = defineExpression({
131
+ expressionKey: 'Numeric.Round',
132
+ builder: (value: Expression<number>, scale: number, roundingMode: RoundingMode) => {
133
+ return { value, scale, roundingMode }
134
+ },
135
+ resolver: ({ value, scale, roundingMode }, evaluate) => {
136
+ return Maths.round(evaluate(value), scale, roundingMode)
137
+ },
138
+ })
139
+
140
+ export const round = RoundExpression.builder
141
+
142
+ export const MinExpression = defineExpression({
143
+ expressionKey: 'Numeric.Min',
144
+ builder: (initialOperands: Array<Expression<number>>) => {
145
+ const operands: Array<Expression<number>> = initialOperands.flatMap((it) => {
146
+ if (isType(it, MinExpression)) {
147
+ return it.operands
148
+ } else {
149
+ return [it]
150
+ }
151
+ })
152
+
153
+ return { operands }
154
+ },
155
+ resolver: ({ operands }, evaluate) => {
156
+ const values = operands.map((it) => evaluate(it))
157
+ return Math.min(...values)
158
+ },
159
+ })
160
+
161
+ export const min = MinExpression.builder
162
+
163
+ export const MaxExpression = defineExpression({
164
+ expressionKey: 'Numeric.Max',
165
+ builder: (initialOperands: Array<Expression<number>>) => {
166
+ const operands: Array<Expression<number>> = initialOperands.flatMap((it) => {
167
+ if (isType(it, MaxExpression)) {
168
+ return it.operands
169
+ } else {
170
+ return [it]
171
+ }
172
+ })
173
+
174
+ return { operands }
175
+ },
176
+ resolver: ({ operands }, evaluate) => {
177
+ const values = operands.map((it) => evaluate(it))
178
+ return Math.max(...values)
179
+ },
180
+ })
181
+
182
+ export const max = MaxExpression.builder
@@ -0,0 +1,38 @@
1
+ import { defineExpression } from '@bessemer/cornerstone/expression/internal'
2
+ import { Expression } from '@bessemer/cornerstone/expression'
3
+
4
+ export const ConcatenateExpression = defineExpression({
5
+ expressionKey: 'Concatenate',
6
+ builder: (first: Expression<string>, second: Expression<string>) => {
7
+ return { first, second }
8
+ },
9
+ resolver: (): string => {
10
+ throw new Error('Not yet implemented')
11
+ },
12
+ })
13
+
14
+ export const concatenate = ConcatenateExpression.builder
15
+
16
+ export const UppercaseExpression = defineExpression({
17
+ expressionKey: 'Uppercase',
18
+ builder: (value: Expression<string>) => {
19
+ return { value }
20
+ },
21
+ resolver: (): string => {
22
+ throw new Error('Not yet implemented')
23
+ },
24
+ })
25
+
26
+ export const uppercase = UppercaseExpression.builder
27
+
28
+ export const SubstringExpression = defineExpression({
29
+ expressionKey: 'Substring',
30
+ builder: (string: Expression<string>, substring: Expression<string>) => {
31
+ return { string, substring }
32
+ },
33
+ resolver: (): boolean => {
34
+ throw new Error('Not yet implemented')
35
+ },
36
+ })
37
+
38
+ export const substring = SubstringExpression.builder
@@ -0,0 +1,48 @@
1
+ import * as NumericExpressions from '@bessemer/cornerstone/expression/numeric-expression'
2
+ import * as StringExpressions from '@bessemer/cornerstone/expression/string-expression'
3
+ import * as ArrayExpressions from '@bessemer/cornerstone/expression/array-expression'
4
+ import * as Expressions from '@bessemer/cornerstone/expression/expression'
5
+ import { NominalType } from '@bessemer/cornerstone/types'
6
+ import { Signable } from '@bessemer/cornerstone/signature'
7
+ import { UnknownRecord } from 'type-fest'
8
+
9
+ export { Expressions, NumericExpressions, StringExpressions, ArrayExpressions }
10
+
11
+ export type ExpressionKey<ReturnType, ArgumentType extends Array<unknown>> = NominalType<string, ['ExpressionKey', ReturnType, ArgumentType]>
12
+
13
+ export type Expression<ReturnType> = ReturnType | IExpression<ReturnType>
14
+
15
+ export interface IExpression<ReturnType> {
16
+ expressionKey: ExpressionKey<ReturnType, Array<unknown>>
17
+ }
18
+
19
+ export interface ExpressionReference<ReturnType, ArgumentType extends Array<unknown>> {
20
+ expressionKey: ExpressionKey<ReturnType, ArgumentType>
21
+ }
22
+
23
+ export interface ReducingExpression<ReturnType, ArgumentType> extends ExpressionReference<ReturnType, [Array<Expression<ArgumentType>>]> {}
24
+
25
+ export type EvaluateExpression = <T>(expression: Expression<T>) => T
26
+
27
+ export type ExpressionDefinition<
28
+ ReturnType,
29
+ ArgumentType extends Array<unknown>,
30
+ ExpressionType extends Expression<ReturnType>
31
+ > = ExpressionReference<ReturnType, ArgumentType> & {
32
+ expressionKey: ExpressionKey<ReturnType, ArgumentType>
33
+ builder: (...parameters: ArgumentType) => ExpressionType
34
+ resolver: (expression: ExpressionType, evaluate: EvaluateExpression, context: ExpressionContext) => ReturnType
35
+ }
36
+
37
+ export interface ExpressionVariable<T> extends IExpression<T> {
38
+ expressionKey: 'Variable'
39
+ name: string
40
+ }
41
+
42
+ export interface ParameterizedVariable<ValueType, ParameterType extends Array<Signable>> {
43
+ apply(...parameters: ParameterType): ExpressionVariable<ValueType>
44
+ }
45
+
46
+ export type ExpressionContext = {
47
+ variables: UnknownRecord
48
+ }
@@ -0,0 +1,3 @@
1
+ import { isFunction as _isFunction } from 'lodash-es'
2
+
3
+ export const isFunction = _isFunction
package/src/glob.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { minimatch } from 'minimatch'
2
+ import { NominalType } from '@bessemer/cornerstone/types'
3
+ import { Zod } from '@bessemer/cornerstone'
4
+ import { ZodType } from 'zod'
5
+
6
+ export type GlobPattern = NominalType<string, 'GlobPattern'>
7
+ export const GlobPatternSchema: ZodType<GlobPattern> = Zod.string()
8
+
9
+ export const schema = (): ZodType<GlobPattern> => {
10
+ return Zod.string()
11
+ }
12
+
13
+ export const match = (str: string, pattern: GlobPattern): boolean => {
14
+ return minimatch(str, pattern)
15
+ }
16
+
17
+ export const anyMatch = (str: string, patterns: Array<GlobPattern>): boolean => {
18
+ return patterns.some((it) => match(str, it))
19
+ }
@@ -0,0 +1,40 @@
1
+ import { evaluate, LazyValue } from '@bessemer/cornerstone/lazy'
2
+ import { isUndefined } from '@bessemer/cornerstone/object'
3
+ import { UnknownRecord } from 'type-fest'
4
+
5
+ export type GlobalVariable<T> = {
6
+ getValue: () => T
7
+ setValue: (value: T) => void
8
+ }
9
+
10
+ let Global: { BessemerGlobalVariables: UnknownRecord }
11
+ if (typeof window !== 'undefined') {
12
+ Global = window as any
13
+ } else if (typeof global !== 'undefined') {
14
+ Global = global as any
15
+ } else {
16
+ Global = globalThis as any
17
+ }
18
+
19
+ if (isUndefined(Global.BessemerGlobalVariables)) {
20
+ Global.BessemerGlobalVariables = {}
21
+ }
22
+
23
+ export const createGlobalVariable = <T>(key: string, defaultValue: LazyValue<T>): GlobalVariable<T> => {
24
+ return {
25
+ getValue: () => {
26
+ const value = Global.BessemerGlobalVariables[key] as T | undefined
27
+
28
+ if (isUndefined(value)) {
29
+ const def = evaluate(defaultValue)
30
+ Global.BessemerGlobalVariables[key] = def
31
+ return def
32
+ }
33
+
34
+ return value
35
+ },
36
+ setValue: (value: T) => {
37
+ Global.BessemerGlobalVariables[key] = value
38
+ },
39
+ }
40
+ }
package/src/hash.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { TaggedType } from '@bessemer/cornerstone/types'
2
+
3
+ export type Hash = TaggedType<string, 'Hash'>
4
+
5
+ export enum HashAlgorithm {
6
+ SHA1 = 'SHA-1',
7
+ SHA256 = 'SHA-256',
8
+ }
9
+
10
+ export const asString = (value: Hash): string => {
11
+ return value
12
+ }
13
+
14
+ export const insecureHash = async (message: string): Promise<Hash> => {
15
+ return hash(message, HashAlgorithm.SHA1)
16
+ }
17
+
18
+ export const secureHash = async (message: string): Promise<Hash> => {
19
+ return hash(message, HashAlgorithm.SHA256)
20
+ }
21
+
22
+ export const hash = async (message: string, algorithm: HashAlgorithm): Promise<Hash> => {
23
+ const msgBuffer = new TextEncoder().encode(message)
24
+ const hashBuffer = await crypto.subtle.digest(algorithm, msgBuffer)
25
+ const hashArray = Array.from(new Uint8Array(hashBuffer))
26
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
27
+ return hashHex as Hash
28
+ }
@@ -0,0 +1,6 @@
1
+ import { NominalType } from '@bessemer/cornerstone/types'
2
+ import { Zod } from '@bessemer/cornerstone/index'
3
+ import { ZodType } from 'zod'
4
+
5
+ export type HexCode = NominalType<string, 'HexCode'>
6
+ export const HexCodeSchema: ZodType<HexCode> = Zod.string().length(7).startsWith('#').describe('A 6-digit hex code starting a # sign')
package/src/index.ts ADDED
@@ -0,0 +1,82 @@
1
+ import * as Objects from '@bessemer/cornerstone/object'
2
+ import * as Functions from '@bessemer/cornerstone/function'
3
+ import * as Arrays from '@bessemer/cornerstone/array'
4
+ import * as Strings from '@bessemer/cornerstone/string'
5
+ import * as Async from '@bessemer/cornerstone/async'
6
+ import * as Maths from '@bessemer/cornerstone/math'
7
+ import * as Sets from '@bessemer/cornerstone/set'
8
+ import * as Dates from '@bessemer/cornerstone/date'
9
+ import * as Comparators from '@bessemer/cornerstone/comparator'
10
+ import * as Equalitors from '@bessemer/cornerstone/equalitor'
11
+ import * as Durations from '@bessemer/cornerstone/duration'
12
+ import * as Uris from '@bessemer/cornerstone/uri'
13
+ import * as Urls from '@bessemer/cornerstone/url'
14
+ import * as Loggers from '@bessemer/cornerstone/logger'
15
+ import * as Errors from '@bessemer/cornerstone/error'
16
+ import * as ErrorEvents from '@bessemer/cornerstone/error-event'
17
+ import * as Preconditions from '@bessemer/cornerstone/precondition'
18
+ import * as Uuids from '@bessemer/cornerstone/uuid'
19
+ import * as Ulids from '@bessemer/cornerstone/ulid'
20
+ import * as Entries from '@bessemer/cornerstone/entry'
21
+ import * as Hashes from '@bessemer/cornerstone/hash'
22
+ import * as Crypto from '@bessemer/cornerstone/crypto'
23
+ import * as Globs from '@bessemer/cornerstone/glob'
24
+
25
+ import * as Zod from '@bessemer/cornerstone/zod'
26
+ import * as Tags from '@bessemer/cornerstone/tag'
27
+ import * as Promises from '@bessemer/cornerstone/promise'
28
+ import * as References from '@bessemer/cornerstone/reference'
29
+ import * as Signatures from '@bessemer/cornerstone/signature'
30
+ import * as Eithers from '@bessemer/cornerstone/either'
31
+ import * as Results from '@bessemer/cornerstone/result'
32
+ import * as Lazy from '@bessemer/cornerstone/lazy'
33
+ import * as Patches from '@bessemer/cornerstone/patch'
34
+ import * as Content from '@bessemer/cornerstone/content'
35
+ import * as Combinables from '@bessemer/cornerstone/combinable'
36
+ import * as Properties from '@bessemer/cornerstone/property'
37
+ import * as RichTexts from '@bessemer/cornerstone/rich-text'
38
+ import * as Retry from '@bessemer/cornerstone/retry'
39
+ import * as Stores from '@bessemer/cornerstone/store'
40
+ import * as Misc from '@bessemer/cornerstone/misc'
41
+
42
+ export {
43
+ Objects,
44
+ Functions,
45
+ Arrays,
46
+ Strings,
47
+ Async,
48
+ Maths,
49
+ Sets,
50
+ Dates,
51
+ Comparators,
52
+ Equalitors,
53
+ Durations,
54
+ Uris,
55
+ Urls,
56
+ Loggers,
57
+ Errors,
58
+ ErrorEvents,
59
+ Preconditions,
60
+ Uuids,
61
+ Ulids,
62
+ Entries,
63
+ Hashes,
64
+ Crypto,
65
+ Globs,
66
+ Zod,
67
+ Tags,
68
+ Promises,
69
+ References,
70
+ Signatures,
71
+ Eithers,
72
+ Results,
73
+ Lazy,
74
+ Patches,
75
+ Content,
76
+ Combinables,
77
+ Properties,
78
+ RichTexts,
79
+ Retry,
80
+ Stores,
81
+ Misc,
82
+ }
package/src/lazy.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { Functions } from '@bessemer/cornerstone'
2
+
3
+ export type LazyValue<T> = T | (() => T)
4
+
5
+ export const evaluate = <T>(value: LazyValue<T>): T => {
6
+ if (Functions.isFunction(value)) {
7
+ return value()
8
+ } else {
9
+ return value
10
+ }
11
+ }