@gesslar/toolkit 0.4.0 → 0.6.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.
@@ -0,0 +1,162 @@
1
+ // Implementation: ../lib/Contract.js
2
+
3
+ import type { ValidateFunction } from 'ajv'
4
+
5
+ /**
6
+ * Debug function type for Contract operations
7
+ */
8
+ export type DebugFunction = (message: string, level?: number, ...args: unknown[]) => void
9
+
10
+ /**
11
+ * Contract represents a successful negotiation between Terms.
12
+ * It handles validation and compatibility checking between what
13
+ * one action provides and what another accepts.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Two-party contract between provider and consumer
18
+ * const provider = new Terms(providerDefinition)
19
+ * const consumer = new Terms(consumerDefinition)
20
+ * const contract = new Contract(provider, consumer, { debug: console.log })
21
+ *
22
+ * // Validate data against the contract
23
+ * const isValid = contract.validate(someData)
24
+ * ```
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // Single-party contract from terms definition
29
+ * const contract = Contract.fromTerms("parser", {
30
+ * provides: {
31
+ * type: "object",
32
+ * properties: {
33
+ * name: { type: "string" },
34
+ * age: { type: "number" }
35
+ * }
36
+ * }
37
+ * })
38
+ *
39
+ * contract.validate({ name: "John", age: 30 }) // true
40
+ * ```
41
+ */
42
+ declare class Contract {
43
+ /**
44
+ * Creates a contract by negotiating between provider and consumer terms
45
+ *
46
+ * @param providerTerms - What the provider offers
47
+ * @param consumerTerms - What the consumer expects
48
+ * @param options - Configuration options
49
+ * @param options.debug - Debug function for logging negotiation details
50
+ *
51
+ * @throws {Sass} If contract negotiation fails due to incompatible terms
52
+ */
53
+ constructor(
54
+ providerTerms: import('./Terms.js').default | null,
55
+ consumerTerms: import('./Terms.js').default | null,
56
+ options?: { debug?: DebugFunction }
57
+ )
58
+
59
+ /**
60
+ * Creates a contract from terms with schema validation
61
+ *
62
+ * @param name - Contract identifier for error reporting
63
+ * @param termsDefinition - The terms definition object
64
+ * @param validator - Optional AJV schema validator function with .errors property
65
+ * @param debug - Debug function for logging validation details
66
+ * @returns New contract instance ready for data validation
67
+ *
68
+ * @throws {Sass} If terms definition is invalid according to the validator
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const contract = Contract.fromTerms("user-parser", {
73
+ * provides: {
74
+ * type: "object",
75
+ * properties: {
76
+ * id: { type: "string" },
77
+ * name: { type: "string" }
78
+ * },
79
+ * required: ["id", "name"]
80
+ * }
81
+ * })
82
+ * ```
83
+ */
84
+ static fromTerms(
85
+ name: string,
86
+ termsDefinition: object,
87
+ validator?: ValidateFunction | null,
88
+ debug?: DebugFunction
89
+ ): Contract
90
+
91
+ /**
92
+ * Validates data against this contract's schema
93
+ *
94
+ * @param data - Data object to validate against the contract
95
+ * @returns True if validation passes
96
+ *
97
+ * @throws {Sass} If validation fails with detailed error messages
98
+ * @throws {Sass} If contract has not been successfully negotiated
99
+ * @throws {Sass} If no validator is available for this contract
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * try {
104
+ * contract.validate({ id: "123", name: "John" })
105
+ * console.log("Data is valid!")
106
+ * } catch (error) {
107
+ * console.error("Validation failed:", error.message)
108
+ * }
109
+ * ```
110
+ */
111
+ validate(data: object): boolean
112
+
113
+ /**
114
+ * Check if contract negotiation was successful
115
+ *
116
+ * @returns True if the contract has been successfully negotiated
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * if (contract.isNegotiated) {
121
+ * contract.validate(data)
122
+ * } else {
123
+ * console.error("Contract negotiation failed")
124
+ * }
125
+ * ```
126
+ */
127
+ get isNegotiated(): boolean
128
+
129
+ /**
130
+ * Get the provider terms (if any)
131
+ *
132
+ * @returns Provider terms or null for single-party contracts
133
+ */
134
+ get providerTerms(): import('./Terms.js').default | null
135
+
136
+ /**
137
+ * Get the consumer terms (if any)
138
+ *
139
+ * @returns Consumer terms or null for single-party contracts
140
+ */
141
+ get consumerTerms(): import('./Terms.js').default | null
142
+
143
+ /**
144
+ * Get the contract validator function
145
+ *
146
+ * @returns The AJV validator function used by this contract, or null if none available
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const validator = contract.validator
151
+ * if (validator) {
152
+ * const isValid = validator(someData)
153
+ * if (!isValid) {
154
+ * console.log("Validation errors:", validator.errors)
155
+ * }
156
+ * }
157
+ * ```
158
+ */
159
+ get validator(): ((data: object) => boolean) | null
160
+ }
161
+
162
+ export default Contract
@@ -21,33 +21,33 @@ export default class Data {
21
21
 
22
22
  /**
23
23
  * Append a suffix string to the end of a string if it doesn't already end with it.
24
- *
25
- * Useful for ensuring strings have consistent endings like file extensions,
24
+ *
25
+ * Useful for ensuring strings have consistent endings like file extensions,
26
26
  * URL paths, or punctuation. Performs case-sensitive comparison and only appends
27
27
  * if the string doesn't already end with the specified suffix.
28
28
  *
29
29
  * @param string - The base string to potentially append to. Can be empty string.
30
30
  * @param append - The suffix to append if not already present. Cannot be empty.
31
31
  * @returns The string with the suffix appended, or the original string if suffix already present
32
- *
32
+ *
33
33
  * @throws {Error} When append parameter is empty or undefined
34
34
  *
35
35
  * @example
36
36
  * ```typescript
37
37
  * import { Data } from '@gesslar/toolkit'
38
- *
38
+ *
39
39
  * // Basic usage with file extensions
40
40
  * const filename = Data.appendString('config', '.json')
41
41
  * console.log(filename) // 'config.json'
42
- *
42
+ *
43
43
  * // No double-appending
44
- * const alreadyHasExt = Data.appendString('package.json', '.json')
44
+ * const alreadyHasExt = Data.appendString('package.json', '.json')
45
45
  * console.log(alreadyHasExt) // 'package.json' (unchanged)
46
- *
46
+ *
47
47
  * // URL path handling
48
48
  * const apiPath = Data.appendString('/api/users', '/')
49
49
  * console.log(apiPath) // '/api/users/'
50
- *
50
+ *
51
51
  * // Works with empty strings
52
52
  * const fromEmpty = Data.appendString('', '.txt')
53
53
  * console.log(fromEmpty) // '.txt'
@@ -57,33 +57,33 @@ export default class Data {
57
57
 
58
58
  /**
59
59
  * Prepend a prefix string to the beginning of a string if it doesn't already start with it.
60
- *
60
+ *
61
61
  * Useful for ensuring strings have consistent beginnings like protocol prefixes,
62
- * path separators, or formatting markers. Performs case-sensitive comparison and
62
+ * path separators, or formatting markers. Performs case-sensitive comparison and
63
63
  * only prepends if the string doesn't already start with the specified prefix.
64
64
  *
65
65
  * @param string - The base string to potentially prepend to. Can be empty string.
66
66
  * @param prepend - The prefix to prepend if not already present. Cannot be empty.
67
67
  * @returns The string with the prefix prepended, or the original string if prefix already present
68
- *
68
+ *
69
69
  * @throws {Error} When prepend parameter is empty or undefined
70
70
  *
71
71
  * @example
72
72
  * ```typescript
73
73
  * import { Data } from '@gesslar/toolkit'
74
- *
74
+ *
75
75
  * // Basic usage with protocols
76
76
  * const url = Data.prependString('example.com', 'https://')
77
77
  * console.log(url) // 'https://example.com'
78
- *
78
+ *
79
79
  * // No double-prepending
80
80
  * const alreadyHasProtocol = Data.prependString('https://api.example.com', 'https://')
81
81
  * console.log(alreadyHasProtocol) // 'https://api.example.com' (unchanged)
82
- *
82
+ *
83
83
  * // File path handling
84
84
  * const absolutePath = Data.prependString('home/user/docs', '/')
85
85
  * console.log(absolutePath) // '/home/user/docs'
86
- *
86
+ *
87
87
  * // CSS class prefixing
88
88
  * const className = Data.prependString('button-primary', 'css-')
89
89
  * console.log(className) // 'css-button-primary'
@@ -135,32 +135,32 @@ export default class Data {
135
135
  static clamped(val: number, min: number, max: number): boolean
136
136
 
137
137
  /**
138
- * Checks if a value is a plain object - created with object literals {},
138
+ * Checks if a value is a plain object - created with object literals {},
139
139
  * new Object(), or Object.create(null).
140
- *
141
- * Distinguishes plain objects from objects created by custom constructors, built-ins,
140
+ *
141
+ * Distinguishes plain objects from objects created by custom constructors, built-ins,
142
142
  * or primitives. Plain objects only have Object.prototype or null in their prototype chain.
143
143
  * Useful for validating configuration objects or data structures that should be plain objects.
144
144
  *
145
145
  * @param value - The value to check for plain object status
146
146
  * @returns True if the value is a plain object, false otherwise
147
- *
147
+ *
148
148
  * @example
149
149
  * ```typescript
150
150
  * import { Data } from '@gesslar/toolkit'
151
- *
151
+ *
152
152
  * // Plain objects return true
153
153
  * console.log(Data.isPlainObject({})) // true
154
- * console.log(Data.isPlainObject(new Object())) // true
154
+ * console.log(Data.isPlainObject(new Object())) // true
155
155
  * console.log(Data.isPlainObject(Object.create(null))) // true
156
- *
156
+ *
157
157
  * // Non-plain objects return false
158
158
  * console.log(Data.isPlainObject([])) // false
159
159
  * console.log(Data.isPlainObject(new Date())) // false
160
160
  * console.log(Data.isPlainObject(/regex/)) // false
161
161
  * console.log(Data.isPlainObject(null)) // false
162
162
  * console.log(Data.isPlainObject('string')) // false
163
- *
163
+ *
164
164
  * // Useful for validating config objects
165
165
  * function processConfig(config: unknown) {
166
166
  * if (!Data.isPlainObject(config)) {
package/src/types/FS.d.ts CHANGED
@@ -9,13 +9,13 @@ import DirectoryObject from './DirectoryObject.js'
9
9
  */
10
10
  export default class FS {
11
11
  /** Array of lowercase file descriptor types */
12
- static readonly fdTypes: readonly ["file", "directory"]
12
+ static readonly fdTypes: readonly ['file', 'directory']
13
13
 
14
14
  /** Array of uppercase file descriptor types */
15
- static readonly upperFdTypes: readonly ["FILE", "DIRECTORY"]
15
+ static readonly upperFdTypes: readonly ['FILE', 'DIRECTORY']
16
16
 
17
17
  /** Mapping from uppercase to lowercase file descriptor types */
18
- static readonly fdType: Readonly<Record<"FILE" | "DIRECTORY", "file" | "directory">>
18
+ static readonly fdType: Readonly<Record<'FILE' | 'DIRECTORY', 'file' | 'directory'>>
19
19
 
20
20
  /** Fix slashes in a path */
21
21
  static fixSlashes(pathName: string): string