sizuku 0.0.7 → 0.2.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 (228) hide show
  1. package/README.md +96 -344
  2. package/dist/cli/main.d.ts +10 -0
  3. package/dist/cli/main.js +61 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +51 -0
  6. package/dist/config/index.d.ts +18 -0
  7. package/dist/config/index.js +13 -0
  8. package/dist/config/loader.d.ts +19 -0
  9. package/dist/config/loader.js +30 -0
  10. package/dist/generator/engine.d.ts +3 -0
  11. package/dist/generator/engine.js +63 -0
  12. package/dist/generator/mermaid-er/config/index.d.ts +4 -4
  13. package/dist/generator/mermaid-er/config/index.js +4 -10
  14. package/dist/generator/mermaid-er/core/extract-relations.d.ts +1 -1
  15. package/dist/generator/mermaid-er/core/extract-relations.js +3 -6
  16. package/dist/generator/mermaid-er/core.d.ts +6 -0
  17. package/dist/generator/mermaid-er/core.js +54 -0
  18. package/dist/generator/mermaid-er/generator/er-content.d.ts +20 -0
  19. package/dist/generator/mermaid-er/generator/{generate-er-content.js → er-content.js} +3 -7
  20. package/dist/generator/mermaid-er/generator/index.d.ts +2 -0
  21. package/dist/generator/mermaid-er/generator/index.js +2 -0
  22. package/dist/generator/mermaid-er/generator/relation-line.d.ts +12 -0
  23. package/dist/generator/mermaid-er/generator/{generate-relation-line.js → relation-line.js} +3 -6
  24. package/dist/generator/mermaid-er/generator.d.ts +3 -0
  25. package/dist/generator/mermaid-er/generator.js +14 -0
  26. package/dist/generator/mermaid-er/index.d.ts +12 -5
  27. package/dist/generator/mermaid-er/index.js +30 -74
  28. package/dist/generator/mermaid-er/relationship/build-relation-line.js +3 -6
  29. package/dist/generator/mermaid-er/types.js +1 -0
  30. package/dist/generator/mermaid-er/validator/index.d.ts +8 -0
  31. package/dist/generator/mermaid-er/validator/index.js +71 -0
  32. package/dist/generator/mermaid-er/validator/is-relationship.d.ts +1 -1
  33. package/dist/generator/mermaid-er/validator/is-relationship.js +1 -4
  34. package/dist/generator/mermaid-er/validator/parse-relation-line.js +1 -4
  35. package/dist/generator/mermaid-er/validator/parse-table-info.d.ts +1 -7
  36. package/dist/generator/mermaid-er/validator/parse-table-info.js +69 -89
  37. package/dist/generator/mermaid-er/validator/remove-duplicate-relations.js +1 -4
  38. package/dist/generator/valibot/config/index.d.ts +2 -2
  39. package/dist/generator/valibot/config/index.js +6 -12
  40. package/dist/generator/valibot/core/extract-schema.d.ts +2 -5
  41. package/dist/generator/valibot/core/extract-schema.js +162 -81
  42. package/dist/generator/valibot/core.d.ts +5 -0
  43. package/dist/generator/valibot/core.js +39 -0
  44. package/dist/generator/valibot/generator/infer-input.d.ts +5 -0
  45. package/dist/generator/valibot/generator/infer-input.js +8 -0
  46. package/dist/generator/valibot/generator/relation-valibot-code.d.ts +13 -0
  47. package/dist/generator/valibot/generator/relation-valibot-code.js +19 -0
  48. package/dist/generator/valibot/generator/valibot-code.d.ts +15 -0
  49. package/dist/generator/valibot/generator/valibot-code.js +16 -0
  50. package/dist/generator/valibot/generator/valibot.d.ts +14 -0
  51. package/dist/generator/valibot/generator/valibot.js +15 -0
  52. package/dist/generator/valibot/generator.d.ts +3 -0
  53. package/dist/generator/valibot/generator.js +14 -0
  54. package/dist/generator/valibot/index.d.ts +14 -3
  55. package/dist/generator/valibot/index.js +46 -73
  56. package/dist/generator/zod/config/index.d.ts +2 -2
  57. package/dist/generator/zod/config/index.js +6 -12
  58. package/dist/generator/zod/core/extract-schema.d.ts +1 -2
  59. package/dist/generator/zod/core/extract-schema.js +228 -81
  60. package/dist/generator/zod/core.d.ts +5 -0
  61. package/dist/generator/zod/core.js +39 -0
  62. package/dist/generator/zod/generator/infer.d.ts +5 -0
  63. package/dist/generator/zod/generator/infer.js +8 -0
  64. package/dist/generator/zod/generator/relation-zod-code.d.ts +13 -0
  65. package/dist/generator/zod/generator/relation-zod-code.js +19 -0
  66. package/dist/generator/zod/generator/zod-code.d.ts +17 -0
  67. package/dist/generator/zod/generator/zod-code.js +18 -0
  68. package/dist/generator/zod/generator/zod.d.ts +16 -0
  69. package/dist/generator/zod/generator/zod.js +16 -0
  70. package/dist/generator/zod/generator.d.ts +3 -0
  71. package/dist/generator/zod/generator.js +14 -0
  72. package/dist/generator/zod/index.d.ts +15 -3
  73. package/dist/generator/zod/index.js +50 -73
  74. package/dist/index.d.ts +8 -0
  75. package/dist/index.js +71 -0
  76. package/dist/shared/config/index.d.ts +13 -0
  77. package/dist/{common → shared}/config/index.js +1 -4
  78. package/dist/shared/format/index.d.ts +15 -0
  79. package/dist/shared/format/index.js +24 -0
  80. package/dist/shared/fs/index.d.ts +7 -0
  81. package/dist/shared/fs/index.js +16 -0
  82. package/dist/shared/fsp/index.d.ts +27 -0
  83. package/dist/shared/fsp/index.js +38 -0
  84. package/dist/shared/generator/field-definitions.d.ts +12 -0
  85. package/dist/shared/generator/field-definitions.js +12 -0
  86. package/dist/shared/helper/ast-parser.d.ts +3 -0
  87. package/dist/shared/helper/ast-parser.js +202 -0
  88. package/dist/shared/helper/build-schema-extractor.d.ts +25 -0
  89. package/dist/shared/helper/build-schema-extractor.js +33 -0
  90. package/dist/shared/helper/create-extract-field-from-property.d.ts +15 -0
  91. package/dist/shared/helper/create-extract-field-from-property.js +20 -0
  92. package/dist/shared/helper/create-extract-fields-from-call-expression.d.ts +14 -0
  93. package/dist/shared/helper/create-extract-fields-from-call-expression.js +14 -0
  94. package/dist/shared/helper/create-extract-relation-field-from-property.d.ts +12 -0
  95. package/dist/shared/helper/create-extract-relation-field-from-property.js +27 -0
  96. package/dist/shared/helper/extract-schemas.d.ts +133 -0
  97. package/dist/shared/helper/extract-schemas.js +445 -0
  98. package/dist/shared/helper/file-writer.d.ts +3 -0
  99. package/dist/shared/helper/file-writer.js +25 -0
  100. package/dist/shared/helper/find-object-literal-expression.d.ts +12 -0
  101. package/dist/shared/helper/find-object-literal-expression.js +31 -0
  102. package/dist/shared/helper/find-object-literalIn-args.d.ts +2 -0
  103. package/dist/shared/helper/find-object-literalIn-args.js +8 -0
  104. package/dist/shared/helper/is-relation-function.d.ts +10 -0
  105. package/dist/shared/helper/is-relation-function.js +16 -0
  106. package/dist/shared/types.js +1 -0
  107. package/dist/{common/text → shared/utils}/capitalize.js +1 -4
  108. package/dist/shared/utils/compose.d.ts +101 -0
  109. package/dist/shared/utils/compose.js +124 -0
  110. package/dist/shared/utils/file.d.ts +92 -0
  111. package/dist/shared/utils/file.js +177 -0
  112. package/dist/shared/utils/functional.d.ts +118 -0
  113. package/dist/shared/utils/functional.js +96 -0
  114. package/dist/shared/utils/index.d.ts +20 -0
  115. package/dist/shared/utils/index.js +48 -0
  116. package/dist/shared/utils/string-utils.d.ts +8 -0
  117. package/dist/shared/utils/string-utils.js +28 -0
  118. package/dist/shared/utils/types.d.ts +32 -0
  119. package/dist/shared/utils/types.js +2 -0
  120. package/dist/shared/utils/validation-utils.d.ts +8 -0
  121. package/dist/shared/utils/validation-utils.js +25 -0
  122. package/dist/src/config/index.d.ts +18 -0
  123. package/dist/src/config/index.js +13 -0
  124. package/dist/src/generator/mermaid-er/core/extract-relations.d.ts +8 -0
  125. package/dist/src/generator/mermaid-er/core/extract-relations.js +12 -0
  126. package/dist/src/generator/mermaid-er/generator/er-content.d.ts +9 -0
  127. package/dist/src/generator/mermaid-er/generator/er-content.js +25 -0
  128. package/dist/src/generator/mermaid-er/generator/index.d.ts +2 -0
  129. package/dist/src/generator/mermaid-er/generator/index.js +2 -0
  130. package/dist/src/generator/mermaid-er/generator/relation-line.d.ts +8 -0
  131. package/dist/src/generator/mermaid-er/generator/relation-line.js +14 -0
  132. package/dist/src/generator/mermaid-er/index.d.ts +6 -0
  133. package/dist/src/generator/mermaid-er/index.js +16 -0
  134. package/dist/src/generator/mermaid-er/relationship/build-relation-line.d.ts +15 -0
  135. package/dist/src/generator/mermaid-er/relationship/build-relation-line.js +35 -0
  136. package/dist/src/generator/mermaid-er/types.d.ts +21 -0
  137. package/dist/src/generator/mermaid-er/types.js +1 -0
  138. package/dist/src/generator/mermaid-er/validator/index.d.ts +4 -0
  139. package/dist/src/generator/mermaid-er/validator/index.js +4 -0
  140. package/dist/src/generator/mermaid-er/validator/is-relationship.d.ts +8 -0
  141. package/dist/src/generator/mermaid-er/validator/is-relationship.js +9 -0
  142. package/dist/src/generator/mermaid-er/validator/parse-relation-line.d.ts +13 -0
  143. package/dist/src/generator/mermaid-er/validator/parse-relation-line.js +21 -0
  144. package/dist/src/generator/mermaid-er/validator/parse-table-info.d.ts +8 -0
  145. package/dist/src/generator/mermaid-er/validator/parse-table-info.js +91 -0
  146. package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +7 -0
  147. package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.js +9 -0
  148. package/dist/src/generator/valibot/generator/infer-input.d.ts +5 -0
  149. package/dist/src/generator/valibot/generator/infer-input.js +8 -0
  150. package/dist/src/generator/valibot/generator/valibot-code.d.ts +14 -0
  151. package/dist/src/generator/valibot/generator/valibot-code.js +16 -0
  152. package/dist/src/generator/valibot/generator/valibot.d.ts +13 -0
  153. package/dist/src/generator/valibot/generator/valibot.js +11 -0
  154. package/dist/src/generator/valibot/index.d.ts +9 -0
  155. package/dist/src/generator/valibot/index.js +34 -0
  156. package/dist/src/generator/zod/generator/infer.d.ts +5 -0
  157. package/dist/src/generator/zod/generator/infer.js +8 -0
  158. package/dist/{generator/zod/generator/generate-zod-code.d.ts → src/generator/zod/generator/zod-code.d.ts} +8 -3
  159. package/dist/src/generator/zod/generator/zod-code.js +18 -0
  160. package/dist/{generator/zod/generator/generate-zod-schema.d.ts → src/generator/zod/generator/zod.d.ts} +8 -4
  161. package/dist/src/generator/zod/generator/zod.js +12 -0
  162. package/dist/src/generator/zod/index.d.ts +10 -0
  163. package/dist/src/generator/zod/index.js +40 -0
  164. package/dist/src/index.d.ts +10 -0
  165. package/dist/src/index.js +35 -0
  166. package/dist/src/shared/format/index.d.ts +2 -0
  167. package/dist/src/shared/format/index.js +10 -0
  168. package/dist/src/shared/fs/index.d.ts +2 -0
  169. package/dist/src/shared/fs/index.js +10 -0
  170. package/dist/src/shared/fsp/index.d.ts +3 -0
  171. package/dist/src/shared/fsp/index.js +8 -0
  172. package/dist/src/shared/generator/field-definitions.d.ts +12 -0
  173. package/dist/src/shared/generator/field-definitions.js +12 -0
  174. package/dist/src/shared/helper/build-schema-extractor.d.ts +25 -0
  175. package/dist/src/shared/helper/build-schema-extractor.js +33 -0
  176. package/dist/src/shared/helper/create-extract-field-from-property.d.ts +15 -0
  177. package/dist/src/shared/helper/create-extract-field-from-property.js +20 -0
  178. package/dist/src/shared/helper/create-extract-fields-from-call-expression.d.ts +14 -0
  179. package/dist/src/shared/helper/create-extract-fields-from-call-expression.js +14 -0
  180. package/dist/src/shared/helper/create-extract-relation-field-from-property.d.ts +12 -0
  181. package/dist/src/shared/helper/create-extract-relation-field-from-property.js +27 -0
  182. package/dist/src/shared/helper/extract-schemas.d.ts +16 -0
  183. package/dist/src/shared/helper/extract-schemas.js +19 -0
  184. package/dist/src/shared/helper/find-object-literal-expression.d.ts +12 -0
  185. package/dist/src/shared/helper/find-object-literal-expression.js +31 -0
  186. package/dist/src/shared/helper/find-object-literalIn-args.d.ts +2 -0
  187. package/dist/src/shared/helper/find-object-literalIn-args.js +8 -0
  188. package/dist/src/shared/helper/is-relation-function.d.ts +10 -0
  189. package/dist/src/shared/helper/is-relation-function.js +16 -0
  190. package/dist/src/shared/utils/index.d.ts +33 -0
  191. package/dist/src/shared/utils/index.js +61 -0
  192. package/dist/utils/index.d.ts +144 -0
  193. package/dist/utils/index.js +301 -0
  194. package/package.json +10 -13
  195. package/dist/common/config/index.d.ts +0 -13
  196. package/dist/common/format/index.d.ts +0 -1
  197. package/dist/common/format/index.js +0 -12
  198. package/dist/common/generator/generate-field-definitions.d.ts +0 -8
  199. package/dist/common/generator/generate-field-definitions.js +0 -16
  200. package/dist/common/helper/get-camel-case-schema-name-helper.d.ts +0 -7
  201. package/dist/common/helper/get-camel-case-schema-name-helper.js +0 -14
  202. package/dist/common/helper/get-pascal-case-schema-name-helper.d.ts +0 -8
  203. package/dist/common/helper/get-pascal-case-schema-name-helper.js +0 -15
  204. package/dist/common/helper/get-variable-name-helper.d.ts +0 -9
  205. package/dist/common/helper/get-variable-name-helper.js +0 -15
  206. package/dist/common/helper/get-variable-schema-name-helper.d.ts +0 -9
  207. package/dist/common/helper/get-variable-schema-name-helper.js +0 -17
  208. package/dist/common/text/decapitalize.d.ts +0 -17
  209. package/dist/common/text/decapitalize.js +0 -22
  210. package/dist/common/type/index.js +0 -2
  211. package/dist/generator/mermaid-er/generator/generate-er-content.d.ts +0 -9
  212. package/dist/generator/mermaid-er/generator/generate-relation-line.d.ts +0 -7
  213. package/dist/generator/mermaid-er/type/index.js +0 -2
  214. package/dist/generator/mermaid-er/validator/is-relation.d.ts +0 -7
  215. package/dist/generator/mermaid-er/validator/is-relation.js +0 -40
  216. package/dist/generator/valibot/generator/generate-valibot-code.d.ts +0 -11
  217. package/dist/generator/valibot/generator/generate-valibot-code.js +0 -21
  218. package/dist/generator/valibot/generator/generate-valibot-infer-input.d.ts +0 -9
  219. package/dist/generator/valibot/generator/generate-valibot-infer-input.js +0 -16
  220. package/dist/generator/valibot/generator/generate-valibot-schema.d.ts +0 -9
  221. package/dist/generator/valibot/generator/generate-valibot-schema.js +0 -16
  222. package/dist/generator/zod/generator/generate-z-infer.d.ts +0 -11
  223. package/dist/generator/zod/generator/generate-z-infer.js +0 -18
  224. package/dist/generator/zod/generator/generate-zod-code.js +0 -21
  225. package/dist/generator/zod/generator/generate-zod-schema.js +0 -17
  226. /package/dist/generator/mermaid-er/{type/index.d.ts → types.d.ts} +0 -0
  227. /package/dist/{common/type/index.d.ts → shared/types.d.ts} +0 -0
  228. /package/dist/{common/text → shared/utils}/capitalize.d.ts +0 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Functional composition utilities for cleaner code
3
+ *
4
+ * @module compose
5
+ */
6
+ /**
7
+ * Pipes a value through a series of functions from left to right
8
+ *
9
+ * @template T - Initial value type
10
+ * @param value - The initial value
11
+ * @param fns - Functions to apply in sequence
12
+ * @returns The final transformed value
13
+ *
14
+ * @example
15
+ * const result = pipe(
16
+ * "hello",
17
+ * str => str.toUpperCase(),
18
+ * str => str + "!",
19
+ * str => str.repeat(2)
20
+ * ) // "HELLO!HELLO!"
21
+ */
22
+ export function pipe(value, ...fns) {
23
+ return fns.reduce((acc, fn) => fn(acc), value);
24
+ }
25
+ /**
26
+ * Composes functions from right to left
27
+ *
28
+ * @param fns - Functions to compose
29
+ * @returns A new function that applies all functions in sequence
30
+ *
31
+ * @example
32
+ * const transform = compose(
33
+ * str => str.repeat(2),
34
+ * str => str + "!",
35
+ * str => str.toUpperCase()
36
+ * )
37
+ * transform("hello") // "HELLO!HELLO!"
38
+ */
39
+ export function compose(...fns) {
40
+ return (arg) => fns.reduceRight((acc, fn) => fn(acc), arg);
41
+ }
42
+ /**
43
+ * Maybe monad for handling nullable values
44
+ *
45
+ * @template T - The wrapped value type
46
+ */
47
+ export class Maybe {
48
+ value;
49
+ constructor(value) {
50
+ this.value = value;
51
+ }
52
+ /**
53
+ * Creates a Maybe from a value
54
+ */
55
+ static of(value) {
56
+ return new Maybe(value);
57
+ }
58
+ /**
59
+ * Creates a Maybe with no value
60
+ */
61
+ static none() {
62
+ return new Maybe(null);
63
+ }
64
+ /**
65
+ * Maps a function over the Maybe value
66
+ */
67
+ map(fn) {
68
+ return this.value == null ? Maybe.none() : Maybe.of(fn(this.value));
69
+ }
70
+ /**
71
+ * Flat maps a function that returns a Maybe
72
+ */
73
+ flatMap(fn) {
74
+ return this.value == null ? Maybe.none() : fn(this.value);
75
+ }
76
+ /**
77
+ * Returns the value or a default
78
+ */
79
+ getOrElse(defaultValue) {
80
+ return this.value == null ? defaultValue : this.value;
81
+ }
82
+ /**
83
+ * Returns the value or null
84
+ */
85
+ getOrNull() {
86
+ return this.value == null ? null : this.value;
87
+ }
88
+ /**
89
+ * Checks if the Maybe has a value
90
+ */
91
+ isSome() {
92
+ return this.value != null;
93
+ }
94
+ /**
95
+ * Checks if the Maybe has no value
96
+ */
97
+ isNone() {
98
+ return this.value == null;
99
+ }
100
+ }
101
+ /**
102
+ * Helper function to create a Maybe
103
+ */
104
+ export const maybe = (value) => Maybe.of(value);
105
+ /**
106
+ * Applies a function only if the condition is true
107
+ *
108
+ * @param condition - The condition to check
109
+ * @param fn - The function to apply
110
+ * @returns A function that conditionally applies the transformation
111
+ */
112
+ export function when(condition, fn) {
113
+ return condition ? fn : (value) => value;
114
+ }
115
+ /**
116
+ * Applies a function only if the predicate returns true
117
+ *
118
+ * @param predicate - The predicate function
119
+ * @param fn - The function to apply
120
+ * @returns A function that conditionally applies the transformation
121
+ */
122
+ export function whenPredicate(predicate, fn) {
123
+ return (value) => (predicate(value) ? fn(value) : value);
124
+ }
@@ -0,0 +1,92 @@
1
+ import { Result } from 'neverthrow'
2
+ export type FileError =
3
+ | {
4
+ type: 'FILE_NOT_FOUND'
5
+ message: string
6
+ }
7
+ | {
8
+ type: 'PERMISSION_DENIED'
9
+ message: string
10
+ }
11
+ | {
12
+ type: 'WRITE_ERROR'
13
+ message: string
14
+ }
15
+ | {
16
+ type: 'READ_ERROR'
17
+ message: string
18
+ }
19
+ | {
20
+ type: 'DIRECTORY_ERROR'
21
+ message: string
22
+ }
23
+ /**
24
+ * Read file synchronously
25
+ */
26
+ export declare function readFileSync(filePath: string): Result<string, FileError>
27
+ /**
28
+ * Read file asynchronously
29
+ */
30
+ export declare function readFileAsync(filePath: string): Promise<Result<string, FileError>>
31
+ /**
32
+ * Write file synchronously
33
+ */
34
+ export declare function writeFileSync(filePath: string, content: string): Result<void, FileError>
35
+ /**
36
+ * Write file asynchronously
37
+ */
38
+ export declare function writeFileAsync(
39
+ filePath: string,
40
+ content: string,
41
+ ): Promise<Result<void, FileError>>
42
+ /**
43
+ * Create directory
44
+ */
45
+ export declare function ensureDirectorySync(dirPath: string): Result<void, FileError>
46
+ /**
47
+ * Create directory asynchronously
48
+ */
49
+ export declare function ensureDirectoryAsync(dirPath: string): Promise<Result<void, FileError>>
50
+ /**
51
+ * Check if file exists
52
+ */
53
+ export declare function fileExists(filePath: string): boolean
54
+ /**
55
+ * Get directory path from file path
56
+ */
57
+ export declare function getDirectoryPath(filePath: string): string
58
+ /**
59
+ * Write file safely (including directory creation)
60
+ */
61
+ export declare function safeWriteFileSync(
62
+ filePath: string,
63
+ content: string,
64
+ ): Result<void, FileError>
65
+ /**
66
+ * Write file safely asynchronously (including directory creation)
67
+ */
68
+ export declare function safeWriteFileAsync(
69
+ filePath: string,
70
+ content: string,
71
+ ): Promise<Result<void, FileError>>
72
+ /**
73
+ * Function to transform file content
74
+ */
75
+ export declare function transformFileContent<T>(
76
+ content: string,
77
+ transformer: (content: string) => Result<T, FileError>,
78
+ ): Result<T, FileError>
79
+ /**
80
+ * Read file, transform it, and return result
81
+ */
82
+ export declare function readAndTransformFileSync<T>(
83
+ filePath: string,
84
+ transformer: (content: string) => Result<T, FileError>,
85
+ ): Result<T, FileError>
86
+ /**
87
+ * Read file asynchronously, transform it, and return result
88
+ */
89
+ export declare function readAndTransformFileAsync<T>(
90
+ filePath: string,
91
+ transformer: (content: string) => Promise<Result<T, FileError>>,
92
+ ): Promise<Result<T, FileError>>
@@ -0,0 +1,177 @@
1
+ // Test run
2
+ // pnpm vitest run src/shared/utils/file.test.ts
3
+ import fs from 'node:fs';
4
+ import fsp from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import { Result, ok, err } from 'neverthrow';
7
+ import { tryCatch, tryCatchAsync } from './functional.js';
8
+ /**
9
+ * Read file synchronously
10
+ */
11
+ export function readFileSync(filePath) {
12
+ return tryCatch(() => fs.readFileSync(filePath, 'utf-8'), (error) => {
13
+ const err = error;
14
+ if (err.code === 'ENOENT') {
15
+ return {
16
+ type: 'FILE_NOT_FOUND',
17
+ message: `File not found: ${filePath}`,
18
+ };
19
+ }
20
+ if (err.code === 'EACCES') {
21
+ return {
22
+ type: 'PERMISSION_DENIED',
23
+ message: `Permission denied: ${filePath}`,
24
+ };
25
+ }
26
+ return {
27
+ type: 'READ_ERROR',
28
+ message: `Failed to read file: ${filePath} - ${err.message}`,
29
+ };
30
+ });
31
+ }
32
+ /**
33
+ * Read file asynchronously
34
+ */
35
+ export async function readFileAsync(filePath) {
36
+ return tryCatchAsync(() => fsp.readFile(filePath, 'utf-8'), (error) => {
37
+ const err = error;
38
+ if (err.code === 'ENOENT') {
39
+ return {
40
+ type: 'FILE_NOT_FOUND',
41
+ message: `File not found: ${filePath}`,
42
+ };
43
+ }
44
+ if (err.code === 'EACCES') {
45
+ return {
46
+ type: 'PERMISSION_DENIED',
47
+ message: `Permission denied: ${filePath}`,
48
+ };
49
+ }
50
+ return {
51
+ type: 'READ_ERROR',
52
+ message: `Failed to read file: ${filePath} - ${err.message}`,
53
+ };
54
+ });
55
+ }
56
+ /**
57
+ * Write file synchronously
58
+ */
59
+ export function writeFileSync(filePath, content) {
60
+ return tryCatch(() => fs.writeFileSync(filePath, content, 'utf-8'), (error) => {
61
+ const err = error;
62
+ if (err.code === 'EACCES') {
63
+ return {
64
+ type: 'PERMISSION_DENIED',
65
+ message: `Permission denied: ${filePath}`,
66
+ };
67
+ }
68
+ return {
69
+ type: 'WRITE_ERROR',
70
+ message: `Failed to write file: ${filePath} - ${err.message}`,
71
+ };
72
+ });
73
+ }
74
+ /**
75
+ * Write file asynchronously
76
+ */
77
+ export async function writeFileAsync(filePath, content) {
78
+ return tryCatchAsync(() => fsp.writeFile(filePath, content, 'utf-8'), (error) => {
79
+ const err = error;
80
+ if (err.code === 'EACCES') {
81
+ return {
82
+ type: 'PERMISSION_DENIED',
83
+ message: `Permission denied: ${filePath}`,
84
+ };
85
+ }
86
+ return {
87
+ type: 'WRITE_ERROR',
88
+ message: `Failed to write file: ${filePath} - ${err.message}`,
89
+ };
90
+ });
91
+ }
92
+ /**
93
+ * Create directory
94
+ */
95
+ export function ensureDirectorySync(dirPath) {
96
+ return tryCatch(() => {
97
+ fs.mkdirSync(dirPath, { recursive: true });
98
+ return undefined;
99
+ }, (error) => {
100
+ const err = error;
101
+ return {
102
+ type: 'DIRECTORY_ERROR',
103
+ message: `Failed to create directory: ${dirPath} - ${err.message}`,
104
+ };
105
+ });
106
+ }
107
+ /**
108
+ * Create directory asynchronously
109
+ */
110
+ export async function ensureDirectoryAsync(dirPath) {
111
+ return tryCatchAsync(async () => {
112
+ await fsp.mkdir(dirPath, { recursive: true });
113
+ return undefined;
114
+ }, (error) => {
115
+ const err = error;
116
+ return {
117
+ type: 'DIRECTORY_ERROR',
118
+ message: `Failed to create directory: ${dirPath} - ${err.message}`,
119
+ };
120
+ });
121
+ }
122
+ /**
123
+ * Check if file exists
124
+ */
125
+ export function fileExists(filePath) {
126
+ return fs.existsSync(filePath);
127
+ }
128
+ /**
129
+ * Get directory path from file path
130
+ */
131
+ export function getDirectoryPath(filePath) {
132
+ return path.dirname(filePath);
133
+ }
134
+ /**
135
+ * Write file safely (including directory creation)
136
+ */
137
+ export function safeWriteFileSync(filePath, content) {
138
+ const dirPath = getDirectoryPath(filePath);
139
+ const createDirResult = ensureDirectorySync(dirPath);
140
+ if (createDirResult.isErr()) {
141
+ return createDirResult;
142
+ }
143
+ return writeFileSync(filePath, content);
144
+ }
145
+ /**
146
+ * Write file safely asynchronously (including directory creation)
147
+ */
148
+ export async function safeWriteFileAsync(filePath, content) {
149
+ const dirPath = getDirectoryPath(filePath);
150
+ const createDirResult = await ensureDirectoryAsync(dirPath);
151
+ if (createDirResult.isErr()) {
152
+ return createDirResult;
153
+ }
154
+ return writeFileAsync(filePath, content);
155
+ }
156
+ /**
157
+ * Function to transform file content
158
+ */
159
+ export function transformFileContent(content, transformer) {
160
+ return transformer(content);
161
+ }
162
+ /**
163
+ * Read file, transform it, and return result
164
+ */
165
+ export function readAndTransformFileSync(filePath, transformer) {
166
+ return readFileSync(filePath).andThen(transformer);
167
+ }
168
+ /**
169
+ * Read file asynchronously, transform it, and return result
170
+ */
171
+ export async function readAndTransformFileAsync(filePath, transformer) {
172
+ const readResult = await readFileAsync(filePath);
173
+ if (readResult.isErr()) {
174
+ return err(readResult.error);
175
+ }
176
+ return transformer(readResult.value);
177
+ }
@@ -0,0 +1,118 @@
1
+ import { Result } from 'neverthrow'
2
+ /**
3
+ * Functional programming utility functions
4
+ */
5
+ /**
6
+ * Compose functions (right to left)
7
+ * compose(f, g)(x) = f(g(x))
8
+ */
9
+ export declare function compose<A, B, C>(f: (b: B) => C, g: (a: A) => B): (a: A) => C
10
+ /**
11
+ * Pipeline functions (left to right)
12
+ * pipe(x, f, g) = g(f(x))
13
+ */
14
+ export declare function pipe<A>(value: A): A
15
+ export declare function pipe<A, B>(value: A, f1: (a: A) => B): B
16
+ export declare function pipe<A, B, C>(value: A, f1: (a: A) => B, f2: (b: B) => C): C
17
+ export declare function pipe<A, B, C, D>(
18
+ value: A,
19
+ f1: (a: A) => B,
20
+ f2: (b: B) => C,
21
+ f3: (c: C) => D,
22
+ ): D
23
+ export declare function pipe<A, B, C, D, E>(
24
+ value: A,
25
+ f1: (a: A) => B,
26
+ f2: (b: B) => C,
27
+ f3: (c: C) => D,
28
+ f4: (d: D) => E,
29
+ ): E
30
+ export declare function pipe<T>(value: T, ...fns: Array<(x: T) => T>): T
31
+ export declare function pipe<T, U>(value: T, f1: (x: T) => U, ...fns: Array<(x: U) => U>): U
32
+ /**
33
+ * Function composition using Result type
34
+ */
35
+ export declare function composeResult<A, B, C, E>(
36
+ f: (b: B) => Result<C, E>,
37
+ g: (a: A) => Result<B, E>,
38
+ ): (a: A) => Result<C, E>
39
+ /**
40
+ * Pipeline processing using Result type
41
+ */
42
+ export declare function pipeResult<A, E>(value: Result<A, E>): Result<A, E>
43
+ export declare function pipeResult<A, B, E>(
44
+ value: Result<A, E>,
45
+ f1: (a: A) => Result<B, E>,
46
+ ): Result<B, E>
47
+ export declare function pipeResult<A, B, C, E>(
48
+ value: Result<A, E>,
49
+ f1: (a: A) => Result<B, E>,
50
+ f2: (b: B) => Result<C, E>,
51
+ ): Result<C, E>
52
+ export declare function pipeResult<A, B, C, D, E>(
53
+ value: Result<A, E>,
54
+ f1: (a: A) => Result<B, E>,
55
+ f2: (b: B) => Result<C, E>,
56
+ f3: (c: C) => Result<D, E>,
57
+ ): Result<D, E>
58
+ export declare function pipeResult<A, B, C, D, F, E>(
59
+ value: Result<A, E>,
60
+ f1: (a: A) => Result<B, E>,
61
+ f2: (b: B) => Result<C, E>,
62
+ f3: (c: C) => Result<D, E>,
63
+ f4: (d: D) => Result<F, E>,
64
+ ): Result<F, E>
65
+ /**
66
+ * Wrap operations with side effects in Result type
67
+ */
68
+ export declare function tryCatch<T, E = Error>(
69
+ fn: () => T,
70
+ errorHandler?: (error: unknown) => E,
71
+ ): Result<T, E>
72
+ /**
73
+ * Wrap asynchronous operations with side effects in Result type
74
+ */
75
+ export declare function tryCatchAsync<T, E = Error>(
76
+ fn: () => Promise<T>,
77
+ errorHandler?: (error: unknown) => E,
78
+ ): Promise<Result<T, E>>
79
+ /**
80
+ * Apply Result type function to each element of array, return result only if all succeed
81
+ */
82
+ export declare function mapResult<A, B, E>(
83
+ items: A[],
84
+ fn: (item: A) => Result<B, E>,
85
+ ): Result<B[], E>
86
+ /**
87
+ * Return Result type based on condition
88
+ */
89
+ export declare function fromPredicate<T, E>(
90
+ predicate: (value: T) => boolean,
91
+ value: T,
92
+ errorFactory: (value: T) => E,
93
+ ): Result<T, E>
94
+ /**
95
+ * Maybe-like null/undefined check
96
+ */
97
+ export declare function fromNullable<T, E>(
98
+ value: T | null | undefined,
99
+ errorFactory: () => E,
100
+ ): Result<T, E>
101
+ /**
102
+ * Combine multiple Result types
103
+ */
104
+ export declare function combine<T1, T2, E>(
105
+ r1: Result<T1, E>,
106
+ r2: Result<T2, E>,
107
+ ): Result<[T1, T2], E>
108
+ export declare function combine<T1, T2, T3, E>(
109
+ r1: Result<T1, E>,
110
+ r2: Result<T2, E>,
111
+ r3: Result<T3, E>,
112
+ ): Result<[T1, T2, T3], E>
113
+ export declare function combine<T1, T2, T3, T4, E>(
114
+ r1: Result<T1, E>,
115
+ r2: Result<T2, E>,
116
+ r3: Result<T3, E>,
117
+ r4: Result<T4, E>,
118
+ ): Result<[T1, T2, T3, T4], E>
@@ -0,0 +1,96 @@
1
+ // Test run
2
+ // pnpm vitest run src/shared/utils/functional.test.ts
3
+ import { Result, ok, err } from 'neverthrow';
4
+ /**
5
+ * Functional programming utility functions
6
+ */
7
+ /**
8
+ * Compose functions (right to left)
9
+ * compose(f, g)(x) = f(g(x))
10
+ */
11
+ export function compose(f, g) {
12
+ return (a) => f(g(a));
13
+ }
14
+ export function pipe(value, ...fns) {
15
+ return fns.reduce((acc, fn) => fn(acc), value);
16
+ }
17
+ /**
18
+ * Function composition using Result type
19
+ */
20
+ export function composeResult(f, g) {
21
+ return (a) => g(a).andThen(f);
22
+ }
23
+ export function pipeResult(value, ...fns) {
24
+ return fns.reduce((acc, fn) => acc.andThen(fn), value);
25
+ }
26
+ /**
27
+ * Wrap operations with side effects in Result type
28
+ */
29
+ export function tryCatch(fn, errorHandler) {
30
+ try {
31
+ return ok(fn());
32
+ }
33
+ catch (error) {
34
+ if (errorHandler) {
35
+ return err(errorHandler(error));
36
+ }
37
+ if (error instanceof Error) {
38
+ return err(error);
39
+ }
40
+ return err(new Error(String(error)));
41
+ }
42
+ }
43
+ /**
44
+ * Wrap asynchronous operations with side effects in Result type
45
+ */
46
+ export async function tryCatchAsync(fn, errorHandler) {
47
+ try {
48
+ const result = await fn();
49
+ return ok(result);
50
+ }
51
+ catch (error) {
52
+ if (errorHandler) {
53
+ return err(errorHandler(error));
54
+ }
55
+ if (error instanceof Error) {
56
+ return err(error);
57
+ }
58
+ return err(new Error(String(error)));
59
+ }
60
+ }
61
+ /**
62
+ * Apply Result type function to each element of array, return result only if all succeed
63
+ */
64
+ export function mapResult(items, fn) {
65
+ const results = [];
66
+ for (const item of items) {
67
+ const result = fn(item);
68
+ if (result.isErr()) {
69
+ return err(result.error);
70
+ }
71
+ results.push(result.value);
72
+ }
73
+ return ok(results);
74
+ }
75
+ /**
76
+ * Return Result type based on condition
77
+ */
78
+ export function fromPredicate(predicate, value, errorFactory) {
79
+ return predicate(value) ? ok(value) : err(errorFactory(value));
80
+ }
81
+ /**
82
+ * Maybe-like null/undefined check
83
+ */
84
+ export function fromNullable(value, errorFactory) {
85
+ return value != null ? ok(value) : err(errorFactory());
86
+ }
87
+ export function combine(...results) {
88
+ const values = [];
89
+ for (const result of results) {
90
+ if (result.isErr()) {
91
+ return err(result.error);
92
+ }
93
+ values.push(result.value);
94
+ }
95
+ return ok(values);
96
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capitalize the first letter of a string.
3
+ *
4
+ * @param str - The input string.
5
+ * @returns A new string with the first letter capitalized.
6
+ */
7
+ export declare function capitalize(str: string): string;
8
+ export declare function schemaName(str: string): string;
9
+ /**
10
+ * Parse field comments and extract definition line and description.
11
+ *
12
+ * @param commentLines - Raw comment lines (e.g., from source text)
13
+ * @param tag - The tag to look for (e.g., '@v.' or '@z.')
14
+ * @returns Parsed definition and description
15
+ */
16
+ export declare function parseFieldComments(commentLines: string[], tag: '@v.' | '@z.'): {
17
+ definition: string;
18
+ description?: string;
19
+ };
20
+ export declare function extractFieldComments(sourceText: string, fieldStartPos: number): string[];
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Capitalize the first letter of a string.
3
+ *
4
+ * @param str - The input string.
5
+ * @returns A new string with the first letter capitalized.
6
+ */
7
+ export function capitalize(str) {
8
+ return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
9
+ }
10
+ export function schemaName(str) {
11
+ return `${str.charAt(0).toUpperCase() + str.slice(1)}Schema`;
12
+ }
13
+ /**
14
+ * Parse field comments and extract definition line and description.
15
+ *
16
+ * @param commentLines - Raw comment lines (e.g., from source text)
17
+ * @param tag - The tag to look for (e.g., '@v.' or '@z.')
18
+ * @returns Parsed definition and description
19
+ */
20
+ export function parseFieldComments(commentLines, tag) {
21
+ const cleaned = commentLines.map((line) => line.replace(/^\/\/\/\s*/, '').trim()).filter(Boolean);
22
+ const definition = cleaned.find((line) => line.startsWith(tag))?.replace(/^@/, '') ?? '';
23
+ const descriptionLines = cleaned.filter((line) => !(line.includes('@z.') || line.includes('@v.') || line.includes('@relation.')));
24
+ const description = descriptionLines.length ? descriptionLines.join(' ') : undefined;
25
+ return { definition, description };
26
+ }
27
+ export function extractFieldComments(sourceText, fieldStartPos) {
28
+ const beforeField = sourceText.substring(0, fieldStartPos);
29
+ const lines = beforeField.split('\n');
30
+ const reverseIndex = lines
31
+ .map((line, index) => ({ line: line.trim(), index }))
32
+ .reverse()
33
+ .reduce((acc, { line }) => {
34
+ if (acc.shouldStop)
35
+ return acc;
36
+ if (line.startsWith('///')) {
37
+ return {
38
+ commentLines: [line, ...acc.commentLines],
39
+ shouldStop: false,
40
+ };
41
+ }
42
+ if (line === '') {
43
+ return acc;
44
+ }
45
+ return { commentLines: acc.commentLines, shouldStop: true };
46
+ }, { commentLines: [], shouldStop: false });
47
+ return reverseIndex.commentLines;
48
+ }
@@ -0,0 +1,8 @@
1
+ export declare const capitalize: (str: string) => string;
2
+ export declare const toPascalCase: (str: string) => string;
3
+ export declare const extractComment: (commentText: string) => string;
4
+ export declare const parseZodTag: (tag: string) => string;
5
+ export declare const parseValibotTag: (tag: string) => string;
6
+ export declare const parseRelationTag: (tag: string) => string;
7
+ export declare const splitLines: (text: string) => string[];
8
+ export declare const joinLines: (lines: string[]) => string;