@kava/kava-api-core 1.0.0 → 1.0.2

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 (133) hide show
  1. package/.github/workflows/publish.yml +40 -0
  2. package/dist/{auth.util.d.ts → auth/auth.d.ts} +1 -5
  3. package/dist/{auth.util.js → auth/auth.js} +38 -30
  4. package/dist/auth/auth.js.map +1 -0
  5. package/dist/auth/index.d.ts +1 -0
  6. package/dist/auth/index.js +2 -0
  7. package/dist/auth/index.js.map +1 -0
  8. package/dist/{context.util.js → context/context.js} +1 -1
  9. package/dist/context/context.js.map +1 -0
  10. package/dist/context/index.d.ts +1 -0
  11. package/dist/context/index.js +2 -0
  12. package/dist/context/index.js.map +1 -0
  13. package/dist/{controller.util.js → controller/controller.js} +1 -1
  14. package/dist/controller/controller.js.map +1 -0
  15. package/dist/controller/index.d.ts +1 -0
  16. package/dist/controller/index.js +2 -0
  17. package/dist/controller/index.js.map +1 -0
  18. package/dist/{conversion.util.js → conversion/conversion.js} +1 -1
  19. package/dist/conversion/conversion.js.map +1 -0
  20. package/dist/conversion/index.d.ts +1 -0
  21. package/dist/conversion/index.js +2 -0
  22. package/dist/conversion/index.js.map +1 -0
  23. package/dist/{db.util.d.ts → db/db.d.ts} +9 -5
  24. package/dist/{db.util.js → db/db.js} +40 -29
  25. package/dist/db/db.js.map +1 -0
  26. package/dist/db/index.d.ts +1 -0
  27. package/dist/db/index.js +2 -0
  28. package/dist/db/index.js.map +1 -0
  29. package/dist/index.d.ts +14 -13
  30. package/dist/index.js +14 -13
  31. package/dist/index.js.map +1 -1
  32. package/dist/logger/index.d.ts +1 -0
  33. package/dist/logger/index.js +2 -0
  34. package/dist/logger/index.js.map +1 -0
  35. package/dist/{logger.util.js → logger/logger.js} +16 -7
  36. package/dist/logger/logger.js.map +1 -0
  37. package/dist/mail/index.d.ts +1 -0
  38. package/dist/mail/index.js +2 -0
  39. package/dist/mail/index.js.map +1 -0
  40. package/dist/{mail.util.js → mail/mail.js} +1 -1
  41. package/dist/mail/mail.js.map +1 -0
  42. package/dist/middleware/index.d.ts +1 -0
  43. package/dist/middleware/index.js +2 -0
  44. package/dist/middleware/index.js.map +1 -0
  45. package/dist/{middleware.util.js → middleware/middleware.js} +1 -1
  46. package/dist/middleware/middleware.js.map +1 -0
  47. package/dist/model/index.d.ts +1 -0
  48. package/dist/model/index.js +2 -0
  49. package/dist/model/index.js.map +1 -0
  50. package/dist/{model.util.js → model/model.js} +1 -1
  51. package/dist/model/model.js.map +1 -0
  52. package/dist/permission/index.d.ts +1 -0
  53. package/dist/permission/index.js +2 -0
  54. package/dist/permission/index.js.map +1 -0
  55. package/dist/{permission.util.js → permission/permission.js} +1 -1
  56. package/dist/permission/permission.js.map +1 -0
  57. package/dist/registry/index.d.ts +1 -0
  58. package/dist/registry/index.js +2 -0
  59. package/dist/registry/index.js.map +1 -0
  60. package/dist/registry/registry.d.ts +28 -0
  61. package/dist/registry/registry.js +19 -0
  62. package/dist/registry/registry.js.map +1 -0
  63. package/dist/route/index.d.ts +1 -0
  64. package/dist/route/index.js +2 -0
  65. package/dist/route/index.js.map +1 -0
  66. package/dist/{route.util.js → route/route.js} +1 -1
  67. package/dist/route/route.js.map +1 -0
  68. package/dist/storage/index.d.ts +1 -0
  69. package/dist/storage/index.js +2 -0
  70. package/dist/storage/index.js.map +1 -0
  71. package/dist/{storage.util.js → storage/storage.js} +2 -2
  72. package/dist/storage/storage.js.map +1 -0
  73. package/dist/validation/index.d.ts +1 -0
  74. package/dist/validation/index.js +2 -0
  75. package/dist/validation/index.js.map +1 -0
  76. package/dist/{validation.util.js → validation/validation.js} +1 -1
  77. package/dist/validation/validation.js.map +1 -0
  78. package/package.json +2 -2
  79. package/src/{auth.util.ts → auth/auth.ts} +255 -241
  80. package/src/auth/index.ts +1 -0
  81. package/src/{context.util.ts → context/context.ts} +17 -17
  82. package/src/context/index.ts +1 -0
  83. package/src/{controller.util.ts → controller/controller.ts} +236 -236
  84. package/src/controller/index.ts +1 -0
  85. package/src/{conversion.util.ts → conversion/conversion.ts} +64 -64
  86. package/src/conversion/index.ts +1 -0
  87. package/src/{db.util.ts → db/db.ts} +420 -405
  88. package/src/db/index.ts +1 -0
  89. package/src/index.ts +14 -13
  90. package/src/logger/index.ts +1 -0
  91. package/src/{logger.util.ts → logger/logger.ts} +176 -169
  92. package/src/mail/index.ts +1 -0
  93. package/src/{mail.util.ts → mail/mail.ts} +85 -85
  94. package/src/middleware/index.ts +1 -0
  95. package/src/{middleware.util.ts → middleware/middleware.ts} +288 -288
  96. package/src/model/index.ts +1 -0
  97. package/src/{model.util.ts → model/model.ts} +2210 -2210
  98. package/src/permission/index.ts +1 -0
  99. package/src/{permission.util.ts → permission/permission.ts} +136 -136
  100. package/src/registry/index.ts +1 -0
  101. package/src/registry/registry.ts +37 -0
  102. package/src/route/index.ts +1 -0
  103. package/src/{route.util.ts → route/route.ts} +11 -11
  104. package/src/storage/index.ts +1 -0
  105. package/src/{storage.util.ts → storage/storage.ts} +101 -101
  106. package/src/validation/index.ts +1 -0
  107. package/src/{validation.util.ts → validation/validation.ts} +338 -338
  108. package/tsconfig.json +1 -1
  109. package/bun.lock +0 -160
  110. package/dist/auth.util.js.map +0 -1
  111. package/dist/context.util.js.map +0 -1
  112. package/dist/controller.util.js.map +0 -1
  113. package/dist/conversion.util.js.map +0 -1
  114. package/dist/db.util.js.map +0 -1
  115. package/dist/logger.util.js.map +0 -1
  116. package/dist/mail.util.js.map +0 -1
  117. package/dist/middleware.util.js.map +0 -1
  118. package/dist/model.util.js.map +0 -1
  119. package/dist/permission.util.js.map +0 -1
  120. package/dist/route.util.js.map +0 -1
  121. package/dist/storage.util.js.map +0 -1
  122. package/dist/validation.util.js.map +0 -1
  123. /package/dist/{context.util.d.ts → context/context.d.ts} +0 -0
  124. /package/dist/{controller.util.d.ts → controller/controller.d.ts} +0 -0
  125. /package/dist/{conversion.util.d.ts → conversion/conversion.d.ts} +0 -0
  126. /package/dist/{logger.util.d.ts → logger/logger.d.ts} +0 -0
  127. /package/dist/{mail.util.d.ts → mail/mail.d.ts} +0 -0
  128. /package/dist/{middleware.util.d.ts → middleware/middleware.d.ts} +0 -0
  129. /package/dist/{model.util.d.ts → model/model.d.ts} +0 -0
  130. /package/dist/{permission.util.d.ts → permission/permission.d.ts} +0 -0
  131. /package/dist/{route.util.d.ts → route/route.d.ts} +0 -0
  132. /package/dist/{storage.util.d.ts → storage/storage.d.ts} +0 -0
  133. /package/dist/{validation.util.d.ts → validation/validation.d.ts} +0 -0
@@ -1,237 +1,237 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import "elysia";
4
- import { Elysia, Context } from "elysia";
5
- import { validate, logger, KeyPermission, db, ValidationRules, ValidationRule } from "@utils";
6
-
7
-
8
-
9
- declare module "elysia" {
10
- interface ControllerContext extends Context {
11
- getQuery : {
12
- paginate : number;
13
- page : number;
14
- sort : string[];
15
- filter : Record<string, string>;
16
- search : string;
17
- searchable : string[];
18
- selectable : string[];
19
- selectableOption : string[];
20
- expand : string[];
21
- };
22
-
23
- responseData : (
24
- data : any[],
25
- totalRow ?: number,
26
- message ?: string,
27
- columns ?: string[],
28
- access ?: string[]
29
- ) => {
30
- status : number;
31
- body : any
32
- };
33
-
34
- validation : <T extends object>(rules: Partial<Record<keyof T | string, ValidationRule[] | string>>) => any;
35
- responseError : (error: any, section?: string, message?: string, debug?: boolean) => any;
36
- responseErrorValidation : (errors: Record<string, string[]>) => any;
37
- responseSaved : (data: any, message?: string) => any;
38
- responseSuccess : (data: any, message?: string) => any;
39
- responseForbidden : (message?: string) => any;
40
- uploadFile : (file: File, folder?: string) => Promise<string>;
41
- deleteFile : (filePath: string) => void;
42
- user ?: any
43
- permissions ?: KeyPermission[],
44
- payload : Record<string, any>
45
- }
46
- }
47
-
48
- export type ValidationRulesFor<T> = Partial<
49
- Record<keyof T | string, ValidationRule[] | string>
50
- >
51
-
52
-
53
- export const controller = (app: Elysia) => app.derive(({ query, body, status }) => ({
54
-
55
- // =====================================>
56
- // ## Basic fetching data query
57
- // =====================================>
58
- getQuery: {
59
- page : query.page ? Number(query.page) : 1,
60
- paginate : query.paginate ? Number(query.paginate) : 10,
61
- search : query.search ? query.search : "",
62
- sort : query.sort ? JSON.parse(query.sort) : ["created_at desc"],
63
- filter : query.filter ? JSON.parse(query.filter) : [],
64
- searchable : query.searchable ? JSON.parse(query.searchable) : [],
65
- selectable : query.selectable ? JSON.parse(query.selectable) : [],
66
- selectableOption : query.selectableOption ? JSON.parse(query.selectableOption) : [],
67
- expand : query.expand ? JSON.parse(query.expand) : [],
68
- },
69
-
70
-
71
-
72
- // ===================================>
73
- // ## Validation request body
74
- // ===================================>
75
- validation: async <T extends object>(
76
- rules: Partial<Record<keyof T | string, ValidationRules[] | string>>
77
- ) => {
78
- const result = await validate(
79
- body as Record<string, any>,
80
- rules as ValidationRules
81
- )
82
-
83
- if (!result.valid) {
84
- throw status(422, {
85
- message: "Error: Unprocessable Entity!",
86
- errors: result.errors,
87
- })
88
- }
89
- },
90
-
91
-
92
-
93
-
94
- // ====================================>
95
- // ## Response error validation
96
- // ====================================>
97
- responseErrorValidation: (errors: Record<string, string[]>) => {
98
- throw status(422, {
99
- message: "Error: Unprocessable Entity!",
100
- errors: errors,
101
- })
102
- },
103
-
104
-
105
-
106
- // ====================================>
107
- // ## Response error
108
- // ====================================>
109
- responseError: (error: any, section?: string, message?: string, debug = (process.env.APP_DEBUG || true)) => {
110
- logger.error(`Error: ${error}`, { error: error, feature: section })
111
-
112
- if (debug) {
113
- throw status(500, {
114
- message : message ?? "Error: Server Side Having Problem!",
115
- error : error?.message ?? "unknown",
116
- section : section ?? "unknown",
117
- })
118
- }
119
-
120
- throw status(500, {
121
- message: message ?? "Error: Server Side Having Problem!"
122
- })
123
- },
124
-
125
-
126
- // ====================================>
127
- // ## Response Forbidden
128
- // ====================================>
129
- responseForbidden: (message?: string) => {
130
- throw status(403, {
131
- message: message ?? "Access Forbidden!"
132
- })
133
- },
134
-
135
-
136
- // ====================================>
137
- // ## Response record
138
- // ====================================>
139
- responseData: (data: any[], totalRow?: number, message?: string) => {
140
- throw status(200, {
141
- message : message ?? (data.length ? "Success" : "Empty data"),
142
- data : data ?? [],
143
- total_row : totalRow ?? null,
144
- });
145
- },
146
-
147
-
148
-
149
- // ===================================>
150
- // ## Response success
151
- // ===================================>
152
- responseSuccess: (data: any, message?: string, code?: 200 | 201) => {
153
- throw status(code || 200, {
154
- message : message ?? "Success",
155
- data : data ?? [],
156
- })
157
- },
158
-
159
-
160
-
161
- // ===================================>
162
- // ## Response saved record
163
- // ===================================>
164
- responseSaved: (data: any, message?: string) => {
165
- throw status(201, {
166
- message : message ?? "Success",
167
- data : data ?? [],
168
- })
169
- },
170
-
171
-
172
-
173
- // ===================================>
174
- // ## Upload file
175
- // ===================================>
176
- uploadFile: async (file: File, folder = "uploads", options?: { disk?: "public" | "private", owner_id?: number, permissions?: { user_id?: number; role_id?: number }[]}): Promise<string> => {
177
- const disk = options?.disk ?? "public"
178
-
179
- const dir = path.resolve("storage", disk, folder);
180
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
181
-
182
- const fileName = `${Date.now().toString(36)}${Math.random().toString(36).substring(2, 18)}${path.extname(file.name).toLowerCase()}`;
183
- const filePath = path.join(dir, fileName);
184
-
185
- const buffer = Buffer.from(await file.arrayBuffer());
186
-
187
- fs.writeFileSync(filePath, buffer);
188
-
189
- const relativePath = `/${folder}/${fileName}`
190
-
191
- if(options) {
192
- const [storage] = await db("storages").insert({
193
- user_id : options?.owner_id ?? null,
194
- disk : disk,
195
- path : relativePath,
196
- filename : file.name,
197
- filetype : file.type,
198
- filesize : buffer.length,
199
- created_at : new Date(),
200
- }).returning(["id"])
201
-
202
- if (options?.permissions?.length) {
203
- const permissions = options.permissions.map(p => ({
204
- storage_id : storage.id,
205
- user_id : p.user_id ?? null,
206
- role_id : p.role_id ?? null,
207
- created_at : new Date(),
208
- }))
209
-
210
- await db("storage_permissions").insert(permissions)
211
- }
212
- }
213
-
214
-
215
- return relativePath
216
- },
217
-
218
-
219
-
220
- // ==================================>
221
- // ## Delete File
222
- // ==================================>
223
- deleteFile: async (filePath: string) => {
224
- if (fs.existsSync(filePath)) {
225
- const record = await db("storages").where("path", filePath).first()
226
-
227
- if(record) {
228
- await db("storages").where("id", record.id).delete()
229
- await db("storage_permissions").where("storage_id", record.id).delete()
230
- }
231
-
232
- fs.unlinkSync(filePath); return true;
233
- }
234
-
235
- return false;
236
- },
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import "elysia";
4
+ import { Elysia, Context } from "elysia";
5
+ import { validate, logger, KeyPermission, db, ValidationRules, ValidationRule } from "@utils";
6
+
7
+
8
+
9
+ declare module "elysia" {
10
+ interface ControllerContext extends Context {
11
+ getQuery : {
12
+ paginate : number;
13
+ page : number;
14
+ sort : string[];
15
+ filter : Record<string, string>;
16
+ search : string;
17
+ searchable : string[];
18
+ selectable : string[];
19
+ selectableOption : string[];
20
+ expand : string[];
21
+ };
22
+
23
+ responseData : (
24
+ data : any[],
25
+ totalRow ?: number,
26
+ message ?: string,
27
+ columns ?: string[],
28
+ access ?: string[]
29
+ ) => {
30
+ status : number;
31
+ body : any
32
+ };
33
+
34
+ validation : <T extends object>(rules: Partial<Record<keyof T | string, ValidationRule[] | string>>) => any;
35
+ responseError : (error: any, section?: string, message?: string, debug?: boolean) => any;
36
+ responseErrorValidation : (errors: Record<string, string[]>) => any;
37
+ responseSaved : (data: any, message?: string) => any;
38
+ responseSuccess : (data: any, message?: string) => any;
39
+ responseForbidden : (message?: string) => any;
40
+ uploadFile : (file: File, folder?: string) => Promise<string>;
41
+ deleteFile : (filePath: string) => void;
42
+ user ?: any
43
+ permissions ?: KeyPermission[],
44
+ payload : Record<string, any>
45
+ }
46
+ }
47
+
48
+ export type ValidationRulesFor<T> = Partial<
49
+ Record<keyof T | string, ValidationRule[] | string>
50
+ >
51
+
52
+
53
+ export const controller = (app: Elysia) => app.derive(({ query, body, status }) => ({
54
+
55
+ // =====================================>
56
+ // ## Basic fetching data query
57
+ // =====================================>
58
+ getQuery: {
59
+ page : query.page ? Number(query.page) : 1,
60
+ paginate : query.paginate ? Number(query.paginate) : 10,
61
+ search : query.search ? query.search : "",
62
+ sort : query.sort ? JSON.parse(query.sort) : ["created_at desc"],
63
+ filter : query.filter ? JSON.parse(query.filter) : [],
64
+ searchable : query.searchable ? JSON.parse(query.searchable) : [],
65
+ selectable : query.selectable ? JSON.parse(query.selectable) : [],
66
+ selectableOption : query.selectableOption ? JSON.parse(query.selectableOption) : [],
67
+ expand : query.expand ? JSON.parse(query.expand) : [],
68
+ },
69
+
70
+
71
+
72
+ // ===================================>
73
+ // ## Validation request body
74
+ // ===================================>
75
+ validation: async <T extends object>(
76
+ rules: Partial<Record<keyof T | string, ValidationRules[] | string>>
77
+ ) => {
78
+ const result = await validate(
79
+ body as Record<string, any>,
80
+ rules as ValidationRules
81
+ )
82
+
83
+ if (!result.valid) {
84
+ throw status(422, {
85
+ message: "Error: Unprocessable Entity!",
86
+ errors: result.errors,
87
+ })
88
+ }
89
+ },
90
+
91
+
92
+
93
+
94
+ // ====================================>
95
+ // ## Response error validation
96
+ // ====================================>
97
+ responseErrorValidation: (errors: Record<string, string[]>) => {
98
+ throw status(422, {
99
+ message: "Error: Unprocessable Entity!",
100
+ errors: errors,
101
+ })
102
+ },
103
+
104
+
105
+
106
+ // ====================================>
107
+ // ## Response error
108
+ // ====================================>
109
+ responseError: (error: any, section?: string, message?: string, debug = (process.env.APP_DEBUG || true)) => {
110
+ logger.error(`Error: ${error}`, { error: error, feature: section })
111
+
112
+ if (debug) {
113
+ throw status(500, {
114
+ message : message ?? "Error: Server Side Having Problem!",
115
+ error : error?.message ?? "unknown",
116
+ section : section ?? "unknown",
117
+ })
118
+ }
119
+
120
+ throw status(500, {
121
+ message: message ?? "Error: Server Side Having Problem!"
122
+ })
123
+ },
124
+
125
+
126
+ // ====================================>
127
+ // ## Response Forbidden
128
+ // ====================================>
129
+ responseForbidden: (message?: string) => {
130
+ throw status(403, {
131
+ message: message ?? "Access Forbidden!"
132
+ })
133
+ },
134
+
135
+
136
+ // ====================================>
137
+ // ## Response record
138
+ // ====================================>
139
+ responseData: (data: any[], totalRow?: number, message?: string) => {
140
+ throw status(200, {
141
+ message : message ?? (data.length ? "Success" : "Empty data"),
142
+ data : data ?? [],
143
+ total_row : totalRow ?? null,
144
+ });
145
+ },
146
+
147
+
148
+
149
+ // ===================================>
150
+ // ## Response success
151
+ // ===================================>
152
+ responseSuccess: (data: any, message?: string, code?: 200 | 201) => {
153
+ throw status(code || 200, {
154
+ message : message ?? "Success",
155
+ data : data ?? [],
156
+ })
157
+ },
158
+
159
+
160
+
161
+ // ===================================>
162
+ // ## Response saved record
163
+ // ===================================>
164
+ responseSaved: (data: any, message?: string) => {
165
+ throw status(201, {
166
+ message : message ?? "Success",
167
+ data : data ?? [],
168
+ })
169
+ },
170
+
171
+
172
+
173
+ // ===================================>
174
+ // ## Upload file
175
+ // ===================================>
176
+ uploadFile: async (file: File, folder = "uploads", options?: { disk?: "public" | "private", owner_id?: number, permissions?: { user_id?: number; role_id?: number }[]}): Promise<string> => {
177
+ const disk = options?.disk ?? "public"
178
+
179
+ const dir = path.resolve("storage", disk, folder);
180
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
181
+
182
+ const fileName = `${Date.now().toString(36)}${Math.random().toString(36).substring(2, 18)}${path.extname(file.name).toLowerCase()}`;
183
+ const filePath = path.join(dir, fileName);
184
+
185
+ const buffer = Buffer.from(await file.arrayBuffer());
186
+
187
+ fs.writeFileSync(filePath, buffer);
188
+
189
+ const relativePath = `/${folder}/${fileName}`
190
+
191
+ if(options) {
192
+ const [storage] = await db("storages").insert({
193
+ user_id : options?.owner_id ?? null,
194
+ disk : disk,
195
+ path : relativePath,
196
+ filename : file.name,
197
+ filetype : file.type,
198
+ filesize : buffer.length,
199
+ created_at : new Date(),
200
+ }).returning(["id"])
201
+
202
+ if (options?.permissions?.length) {
203
+ const permissions = options.permissions.map(p => ({
204
+ storage_id : storage.id,
205
+ user_id : p.user_id ?? null,
206
+ role_id : p.role_id ?? null,
207
+ created_at : new Date(),
208
+ }))
209
+
210
+ await db("storage_permissions").insert(permissions)
211
+ }
212
+ }
213
+
214
+
215
+ return relativePath
216
+ },
217
+
218
+
219
+
220
+ // ==================================>
221
+ // ## Delete File
222
+ // ==================================>
223
+ deleteFile: async (filePath: string) => {
224
+ if (fs.existsSync(filePath)) {
225
+ const record = await db("storages").where("path", filePath).first()
226
+
227
+ if(record) {
228
+ await db("storages").where("id", record.id).delete()
229
+ await db("storage_permissions").where("storage_id", record.id).delete()
230
+ }
231
+
232
+ fs.unlinkSync(filePath); return true;
233
+ }
234
+
235
+ return false;
236
+ },
237
237
  }));
@@ -0,0 +1 @@
1
+ export * from "./controller";
@@ -1,65 +1,65 @@
1
- export const conversion = {
2
-
3
- // =============================>
4
- // ## Conversion: String formatter
5
- // =============================>
6
- strSnake(value: string, delimiter: string = "_"): string {
7
- return toWords(value).join(delimiter)
8
- },
9
-
10
- strSlug(value: string, delimiter: string = "-"): string {
11
- return toWords(value).join(delimiter);
12
- },
13
-
14
- strCamel(value: string, delimiter: string = ""): string {
15
- return toWords(value).map((w, i) => i === 0 ? w : w[0].toUpperCase() + w.slice(1)).join(delimiter);
16
- },
17
-
18
- strPascal(value: string, delimiter: string = ""): string {
19
- return toWords(value).map(w => w[0].toUpperCase() + w.slice(1)).join(delimiter);
20
- },
21
-
22
- strPlural(value: string): string {
23
- const match = value.match(/^(.*?)([A-Za-z]+)$/)
24
- if (!match) return value
25
-
26
- const [, prefix, word] = match
27
-
28
- if (word.endsWith("y") && !/[aeiou]y$/i.test(word)) {
29
- return prefix + word.slice(0, -1) + "ies"
30
- }
31
-
32
- if (!word.endsWith("s")) return prefix + word + "s"
33
-
34
- return value
35
- },
36
-
37
- strSingular(value: string): string {
38
- const match = value.match(/^(.*?)([A-Za-z]+)$/)
39
- if (!match) return value
40
-
41
- const [, prefix, word] = match
42
-
43
- if (word.endsWith("ies")) {
44
- return prefix + word.slice(0, -3) + "y"
45
- }
46
-
47
- if (word.endsWith("s") && !word.endsWith("ss")) {
48
- return prefix + word.slice(0, -1)
49
- }
50
-
51
- return value
52
- }
53
- };
54
-
55
-
56
-
57
- function toWords(value: string): string[] {
58
- return value
59
- .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
60
- .replace(/[_\-\s]+/g, " ")
61
- .trim()
62
- .toLowerCase()
63
- .split(" ")
64
- .filter(Boolean)
1
+ export const conversion = {
2
+
3
+ // =============================>
4
+ // ## Conversion: String formatter
5
+ // =============================>
6
+ strSnake(value: string, delimiter: string = "_"): string {
7
+ return toWords(value).join(delimiter)
8
+ },
9
+
10
+ strSlug(value: string, delimiter: string = "-"): string {
11
+ return toWords(value).join(delimiter);
12
+ },
13
+
14
+ strCamel(value: string, delimiter: string = ""): string {
15
+ return toWords(value).map((w, i) => i === 0 ? w : w[0].toUpperCase() + w.slice(1)).join(delimiter);
16
+ },
17
+
18
+ strPascal(value: string, delimiter: string = ""): string {
19
+ return toWords(value).map(w => w[0].toUpperCase() + w.slice(1)).join(delimiter);
20
+ },
21
+
22
+ strPlural(value: string): string {
23
+ const match = value.match(/^(.*?)([A-Za-z]+)$/)
24
+ if (!match) return value
25
+
26
+ const [, prefix, word] = match
27
+
28
+ if (word.endsWith("y") && !/[aeiou]y$/i.test(word)) {
29
+ return prefix + word.slice(0, -1) + "ies"
30
+ }
31
+
32
+ if (!word.endsWith("s")) return prefix + word + "s"
33
+
34
+ return value
35
+ },
36
+
37
+ strSingular(value: string): string {
38
+ const match = value.match(/^(.*?)([A-Za-z]+)$/)
39
+ if (!match) return value
40
+
41
+ const [, prefix, word] = match
42
+
43
+ if (word.endsWith("ies")) {
44
+ return prefix + word.slice(0, -3) + "y"
45
+ }
46
+
47
+ if (word.endsWith("s") && !word.endsWith("ss")) {
48
+ return prefix + word.slice(0, -1)
49
+ }
50
+
51
+ return value
52
+ }
53
+ };
54
+
55
+
56
+
57
+ function toWords(value: string): string[] {
58
+ return value
59
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
60
+ .replace(/[_\-\s]+/g, " ")
61
+ .trim()
62
+ .toLowerCase()
63
+ .split(" ")
64
+ .filter(Boolean)
65
65
  }
@@ -0,0 +1 @@
1
+ export * from "./conversion";