@medyll/idae-engine 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # @medyll/engine
2
+
3
+ A powerful TypeScript library for data manipulation and operations across the idae-engine.
4
+
5
+ ## Installation
6
+
7
+ Install the package using npm:
8
+
9
+ ```bash
10
+ npm install @medyll/idae-engine
11
+ ```
12
+
13
+ Or using yarn:
14
+
15
+ ```bash
16
+ yarn add @medyll/idae-engine
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ The `@medyll/idae-eengine` package contains several utility classes. This section focuses on the `dataOp` class, which provides various data manipulation methods.
22
+
23
+ ### Importing
24
+
25
+ ```typescript
26
+ import { dataOp } from '@medyll/idae-engine';
27
+ ```
28
+ ## dataOp
29
+ ### Methods
30
+
31
+ #### do
32
+
33
+ Performs a combination of sort, find, and group operations on data.
34
+
35
+ ```typescript
36
+ const result = dataOp.do({
37
+ sort: { arr: myArray, by: 'fieldName', sort: 'asc' },
38
+ find: { arr: myArray, kw: 'searchTerm', field: 'fieldName' },
39
+ group: { dataList: myArray, groupBy: 'fieldName' }
40
+ });
41
+ ```
42
+
43
+ #### sortBy
44
+
45
+ Sorts an array of objects based on specified fields.
46
+
47
+ ```typescript
48
+ const sortedArray = dataOp.sortBy({
49
+ arr: myArray,
50
+ by: 'fieldName',
51
+ sort: 'asc'
52
+ });
53
+ ```
54
+
55
+ #### find
56
+
57
+ Searches for objects in an array based on specified criteria.
58
+
59
+ ```typescript
60
+ const foundItems = dataOp.find({
61
+ arr: myArray,
62
+ kw: 'searchTerm',
63
+ field: 'fieldName'
64
+ });
65
+ ```
66
+
67
+ #### findOne
68
+
69
+ Searches for the first object in an array that matches the specified criteria.
70
+
71
+ ```typescript
72
+ const foundItem = dataOp.findOne({
73
+ arr: myArray,
74
+ kw: 'searchTerm',
75
+ field: 'fieldName'
76
+ });
77
+ ```
78
+
79
+ #### groupBy
80
+
81
+ Groups objects in an array based on specified fields or a custom grouping function.
82
+
83
+ ```typescript
84
+ const groupedData = dataOp.groupBy({
85
+ dataList: myArray,
86
+ groupBy: 'fieldName'
87
+ });
88
+ ```
89
+
90
+ #### findByIndex
91
+
92
+ Finds the index of an object in an array based on a specified key-value pair.
93
+
94
+ ```typescript
95
+ const index = dataOp.findByIndex(myArray, 'value', 'keyName');
96
+ ```
97
+
98
+ #### resolveDotPath
99
+
100
+ Resolves a dot-notated path in an object.
101
+
102
+ ```typescript
103
+ const value = dataOp.resolveDotPath(myObject, 'path.to.property');
104
+ ```
105
+
106
+ ### Testing
107
+
108
+ The `dataOp` class comes with a comprehensive test suite. To run the tests:
109
+
110
+ 1. Clone the repository
111
+ 2. Install dependencies: `npm install` or `yarn install`
112
+ 3. Run tests: `npm test` or `yarn test`
113
+
114
+ The tests cover various scenarios for each method, ensuring the reliability and correctness of the `dataOp` class.
115
+
116
+ ## Contributing
117
+
118
+ Contributions are welcome! Please feel free to submit a Pull Request.
119
+
120
+ ## License
121
+
122
+ This project is licensed under the MIT License.
@@ -0,0 +1,122 @@
1
+ import { type ResolverPathType } from "./types.js";
2
+ type Data = Record<string, any>;
3
+ export type DataGroupResult<T> = {
4
+ [key: string]: {
5
+ title: string;
6
+ code?: string;
7
+ data: T[];
8
+ };
9
+ };
10
+ type DataSortBy<T> = {
11
+ arr: T[];
12
+ by: Partial<Record<ResolverPathType<T>, "asc" | "desc" | 1 | -1 | undefined>>;
13
+ options?: {
14
+ keepRef: true;
15
+ };
16
+ } | {
17
+ arr: T[];
18
+ by: ResolverPathType<T> | ResolverPathType<T>[];
19
+ sort?: "asc" | "desc" | 1 | -1 | undefined;
20
+ options?: {
21
+ keepRef: true;
22
+ };
23
+ };
24
+ type DataFind<T> = {
25
+ kw: number | string;
26
+ arr: T[];
27
+ field?: ResolverPathType<T> | "*";
28
+ caseSensitive?: boolean;
29
+ strict?: false;
30
+ };
31
+ type DataGroupBy<T> = {
32
+ dataList: T[];
33
+ groupBy: ((item: T) => {
34
+ title: string;
35
+ code: string;
36
+ }) | ResolverPathType<T> | ResolverPathType<T>[];
37
+ keepUngroupedData?: boolean;
38
+ };
39
+ /** data manipulation class */
40
+ export declare class dataOp {
41
+ /**
42
+ * Performs a combination of sort, find, and group operations on data.
43
+ *
44
+ * @template T - The type of objects in the array, extends Data.
45
+ * @param {Object} options - The options for data operations.
46
+ * @param {DataSortBy<T>} [options.sort] - Sorting options.
47
+ * @param {DataFind<T>} [options.find] - Finding options.
48
+ * @param {DataGroupBy<T>} [options.group] - Grouping options.
49
+ * @returns {T[] | GroupResult<T>} The resulting array or grouped data.
50
+ */
51
+ static do<T extends Data>(options: {
52
+ sort?: DataSortBy<T>;
53
+ find?: DataFind<T>;
54
+ group?: DataGroupBy<T>;
55
+ }): T[] | DataGroupResult<T>;
56
+ /**
57
+ * Sorts an array of objects based on one or more specified fields with individual sort directions.
58
+ *
59
+ * @template T - The type of objects in the array, extends Data.
60
+ * @param {DataSortBy<T>} sortOptions - The sorting options.
61
+ * @returns {T[]} The sorted array.
62
+ */
63
+ static sortBy<T extends Data>(sortOptions: DataSortBy<T>): T[];
64
+ /**
65
+ * Searches for objects in an array based on specified criteria.
66
+ *
67
+ * @template T - The type of objects in the array, defaults to Record<string, unknown>.
68
+ * @param {Object} options - The search options.
69
+ * @param {number|string} options.kw - The keyword to search for.
70
+ * @param {T[]} options.in - The array to search in.
71
+ * @param {(keyof T | ResolverPathType<T> | "*")} [options.field="*"] - The field to search in. Use "*" to search in all fields.
72
+ * @param {boolean} [options.caseSensitive=false] - Whether the search should be case-sensitive.
73
+ * @returns {T[]} An array of objects that match the search criteria.
74
+ */
75
+ static find<T extends object = Record<string, unknown>>(options: DataFind<T>): T[];
76
+ /**
77
+ * Searches for the first object in an array that matches the specified criteria.
78
+ *
79
+ * @template T - The type of objects in the array, defaults to Record<string, unknown>.
80
+ * @param {Object} options - The search options.
81
+ * @param {T[]} options.arr - The array to search in.
82
+ * @param {number|string} options.kw - The keyword to search for.
83
+ * @param {(ResolverPathType<T> | "*")} [options.field="*"] - The field to search in. Use "*" to search in all fields.
84
+ * @param {boolean} [options.caseSensitive=false] - Whether the search should be case-sensitive.
85
+ * @returns {T | undefined} The first object that matches the search criteria, or undefined if no match is found.
86
+ */
87
+ static findOne<T extends Data>(options: DataFind<T>): T | undefined;
88
+ /**
89
+ * Groups objects in an array based on specified fields or a custom grouping function.
90
+ *
91
+ * @template T - The type of objects in the array, defaults to Data.
92
+ * @param {Object} options - The grouping options.
93
+ * @param {T[]} options.dataList - The array to group.
94
+ * @param {((item: T) => { title: string; code: string }) | ResolverPathType<T> | ResolverPathType<T>[]} options.groupBy - The field(s) to group by or a function to determine the group.
95
+ * @param {boolean} [options.keepUngroupedData=false] - Whether to keep ungrouped data.
96
+ * @returns {DataGroupResult<T>} An object where keys are group codes and values are objects containing title, code, and data array.
97
+ */
98
+ static groupBy<T = Data>(options: DataGroupBy<T>): DataGroupResult<T>;
99
+ /**
100
+ *
101
+ * @param arr array to find in
102
+ * @param value value to seek for
103
+ * @param key object key to match with
104
+ * @returns number
105
+ */
106
+ static findByIndex<T = Record<string, any>>(arr: T[], value: any, key?: keyof T | ResolverPathType<T>): number;
107
+ static resolveDotPath<T = Data>(object: T, path: ResolverPathType<T>, defaultValue?: any): any;
108
+ /**
109
+ * Compares two values for sorting.
110
+ *
111
+ * @private
112
+ * @template T - The type of objects being compared.
113
+ * @param {T} a - The first object to compare.
114
+ * @param {T} b - The second object to compare.
115
+ * @param {ResolverPathType<T>} field - The field to compare.
116
+ * @param {number} sortD - The sort direction (1 for ascending, -1 for descending).
117
+ * @returns {number} The comparison result.
118
+ */
119
+ private static compareValues;
120
+ private static compareSearchValues;
121
+ }
122
+ export {};
@@ -0,0 +1,195 @@
1
+ import {} from "./types.js";
2
+ /** data manipulation class */
3
+ export class dataOp {
4
+ /**
5
+ * Performs a combination of sort, find, and group operations on data.
6
+ *
7
+ * @template T - The type of objects in the array, extends Data.
8
+ * @param {Object} options - The options for data operations.
9
+ * @param {DataSortBy<T>} [options.sort] - Sorting options.
10
+ * @param {DataFind<T>} [options.find] - Finding options.
11
+ * @param {DataGroupBy<T>} [options.group] - Grouping options.
12
+ * @returns {T[] | GroupResult<T>} The resulting array or grouped data.
13
+ */
14
+ static do(options) {
15
+ let result = options.sort?.arr || options.find?.arr || options.group?.dataList || [];
16
+ if (options.sort) {
17
+ result = this.sortBy(options.sort);
18
+ }
19
+ if (options.find) {
20
+ result = this.find({ ...options.find, arr: result });
21
+ }
22
+ if (options.group) {
23
+ return this.groupBy({ ...options.group, dataList: result });
24
+ }
25
+ return result;
26
+ }
27
+ /**
28
+ * Sorts an array of objects based on one or more specified fields with individual sort directions.
29
+ *
30
+ * @template T - The type of objects in the array, extends Data.
31
+ * @param {DataSortBy<T>} sortOptions - The sorting options.
32
+ * @returns {T[]} The sorted array.
33
+ */
34
+ static sortBy(sortOptions) {
35
+ const { arr, options } = sortOptions;
36
+ const sortArray = options?.keepRef ? arr : [...arr];
37
+ if (!sortOptions.by ||
38
+ (Array.isArray(sortOptions.by) && sortOptions.by.length === 0)) {
39
+ return sortArray;
40
+ }
41
+ return sortArray.sort((a, b) => {
42
+ if ("sort" in sortOptions) {
43
+ const { by, sort = "asc" } = sortOptions;
44
+ const sortD = sort === "asc" || sort === 1 ? 1 : -1;
45
+ const fields = Array.isArray(by) ? by : [by];
46
+ for (const field of fields) {
47
+ const comparison = this.compareValues(a, b, field, sortD);
48
+ if (comparison !== 0)
49
+ return comparison;
50
+ }
51
+ }
52
+ else {
53
+ for (const [field, direction] of Object.entries(sortOptions.by)) {
54
+ const sortD = direction === "asc" || Number(direction) === 1 ? 1 : -1;
55
+ const comparison = this.compareValues(a, b, field, sortD);
56
+ if (comparison !== 0)
57
+ return comparison;
58
+ }
59
+ }
60
+ return 0;
61
+ });
62
+ }
63
+ /**
64
+ * Searches for objects in an array based on specified criteria.
65
+ *
66
+ * @template T - The type of objects in the array, defaults to Record<string, unknown>.
67
+ * @param {Object} options - The search options.
68
+ * @param {number|string} options.kw - The keyword to search for.
69
+ * @param {T[]} options.in - The array to search in.
70
+ * @param {(keyof T | ResolverPathType<T> | "*")} [options.field="*"] - The field to search in. Use "*" to search in all fields.
71
+ * @param {boolean} [options.caseSensitive=false] - Whether the search should be case-sensitive.
72
+ * @returns {T[]} An array of objects that match the search criteria.
73
+ */
74
+ static find(options) {
75
+ const { arr, kw, field = "*", caseSensitive = false, strict = false, } = options;
76
+ return arr.filter((item) => {
77
+ if (field !== "*") {
78
+ const itemValue = this.resolveDotPath(item, field);
79
+ return this.compareSearchValues(itemValue, kw, caseSensitive, strict);
80
+ }
81
+ return Object.values(item).some((value) => this.compareSearchValues(value, kw, caseSensitive, strict));
82
+ });
83
+ }
84
+ /**
85
+ * Searches for the first object in an array that matches the specified criteria.
86
+ *
87
+ * @template T - The type of objects in the array, defaults to Record<string, unknown>.
88
+ * @param {Object} options - The search options.
89
+ * @param {T[]} options.arr - The array to search in.
90
+ * @param {number|string} options.kw - The keyword to search for.
91
+ * @param {(ResolverPathType<T> | "*")} [options.field="*"] - The field to search in. Use "*" to search in all fields.
92
+ * @param {boolean} [options.caseSensitive=false] - Whether the search should be case-sensitive.
93
+ * @returns {T | undefined} The first object that matches the search criteria, or undefined if no match is found.
94
+ */
95
+ static findOne(options) {
96
+ const { arr, kw, field = "*", caseSensitive = false, strict = false, } = options;
97
+ return arr.find((item) => {
98
+ if (field !== "*") {
99
+ const itemValue = this.resolveDotPath(item, field);
100
+ return this.compareSearchValues(itemValue, kw, caseSensitive, strict);
101
+ }
102
+ return Object.values(item).some((value) => this.compareSearchValues(value, kw, caseSensitive, strict));
103
+ });
104
+ }
105
+ /**
106
+ * Groups objects in an array based on specified fields or a custom grouping function.
107
+ *
108
+ * @template T - The type of objects in the array, defaults to Data.
109
+ * @param {Object} options - The grouping options.
110
+ * @param {T[]} options.dataList - The array to group.
111
+ * @param {((item: T) => { title: string; code: string }) | ResolverPathType<T> | ResolverPathType<T>[]} options.groupBy - The field(s) to group by or a function to determine the group.
112
+ * @param {boolean} [options.keepUngroupedData=false] - Whether to keep ungrouped data.
113
+ * @returns {DataGroupResult<T>} An object where keys are group codes and values are objects containing title, code, and data array.
114
+ */
115
+ static groupBy(options) {
116
+ const { dataList, groupBy: groupField, keepUngroupedData = false, } = options;
117
+ return dataList.reduce((result, currentItem) => {
118
+ let groupInfo;
119
+ if (typeof groupField === "function") {
120
+ groupInfo = groupField(currentItem);
121
+ }
122
+ else {
123
+ const fields = Array.isArray(groupField) ? groupField : [groupField];
124
+ const groupValue = fields
125
+ .map((field) => this.resolveDotPath(currentItem, field))
126
+ .filter((value) => value !== undefined)
127
+ .join(".");
128
+ if (groupValue) {
129
+ groupInfo = { title: groupValue, code: groupValue };
130
+ }
131
+ }
132
+ if (!groupInfo) {
133
+ if (!keepUngroupedData)
134
+ return result;
135
+ groupInfo = { title: "- Ungrouped", code: "- ungrouped" };
136
+ }
137
+ const groupKey = groupInfo.code;
138
+ if (!result[groupKey]) {
139
+ result[groupKey] = {
140
+ title: groupInfo.title,
141
+ code: groupInfo.code,
142
+ data: [],
143
+ };
144
+ }
145
+ result[groupKey].data.push(currentItem);
146
+ return result;
147
+ }, {});
148
+ }
149
+ /**
150
+ *
151
+ * @param arr array to find in
152
+ * @param value value to seek for
153
+ * @param key object key to match with
154
+ * @returns number
155
+ */
156
+ static findByIndex(arr, value, key = "id") {
157
+ return arr.findIndex((obj) => this.resolveDotPath(obj, key) === value);
158
+ }
159
+ static resolveDotPath(object, path, defaultValue) {
160
+ return path
161
+ .split(".")
162
+ .reduce((r, s) => (r && typeof r === "object" && s in r ? r[s] : defaultValue), object);
163
+ }
164
+ /**
165
+ * Compares two values for sorting.
166
+ *
167
+ * @private
168
+ * @template T - The type of objects being compared.
169
+ * @param {T} a - The first object to compare.
170
+ * @param {T} b - The second object to compare.
171
+ * @param {ResolverPathType<T>} field - The field to compare.
172
+ * @param {number} sortD - The sort direction (1 for ascending, -1 for descending).
173
+ * @returns {number} The comparison result.
174
+ */
175
+ static compareValues(a, b, field, sortD) {
176
+ const aValue = this.resolveDotPath(a, field);
177
+ const bValue = this.resolveDotPath(b, field);
178
+ if (typeof aValue === "string" && typeof bValue === "string") {
179
+ return sortD * aValue.localeCompare(bValue);
180
+ }
181
+ return sortD * (aValue > bValue ? 1 : aValue < bValue ? -1 : 0);
182
+ }
183
+ static compareSearchValues(itemValue, searchValue, caseSensitive, strict) {
184
+ const strItemValue = String(itemValue);
185
+ const strSearchValue = String(searchValue);
186
+ if (strict) {
187
+ return caseSensitive
188
+ ? strItemValue === strSearchValue
189
+ : strItemValue.toLowerCase() === strSearchValue.toLowerCase();
190
+ }
191
+ return caseSensitive
192
+ ? strItemValue.includes(strSearchValue)
193
+ : strItemValue.toLowerCase().includes(strSearchValue.toLowerCase());
194
+ }
195
+ }
@@ -0,0 +1,3 @@
1
+ export type ResolverPathType<T> = T extends object ? {
2
+ [K in keyof T]: (K & string) | (T[K] extends object ? `${K & string}.${ResolverPathType<T[K]>}` : never);
3
+ }[keyof T] : never;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './dataOp/dataOp.js';
2
+ export * from './dataOp/types.js';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // Reexport of entry components
2
+ export * from './dataOp/dataOp.js';
3
+ export * from './dataOp/types.js';
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@medyll/idae-engine",
3
+ "scope": "@medyll",
4
+ "version": "1.0.0",
5
+ "scripts": {
6
+ "dev": "vite dev",
7
+ "build": "vite build && npm run package",
8
+ "preview": "vite preview",
9
+ "package": "svelte-kit sync && svelte-package && publint",
10
+ "package:watch": "svelte-kit sync && svelte-package --watch",
11
+ "prepublishOnly": "npm run package",
12
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
13
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
14
+ "test": "vitest"
15
+ },
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "svelte": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "!dist/**/*.test.*",
25
+ "!dist/**/*.spec.*"
26
+ ],
27
+ "peerDependencies": {
28
+ "svelte": "^4.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@sveltejs/adapter-auto": "^3.0.0",
32
+ "@sveltejs/kit": "^2.0.0",
33
+ "@sveltejs/package": "^2.0.0",
34
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
35
+ "publint": "^0.1.9",
36
+ "svelte": "^5.0.0-next.183",
37
+ "svelte-check": "^3.6.0",
38
+ "tslib": "^2.4.1",
39
+ "typescript": "^5.0.0",
40
+ "vite": "^5.0.11",
41
+ "vitest": "^1.2.0"
42
+ },
43
+ "svelte": "./dist/index.js",
44
+ "types": "./dist/index.d.ts",
45
+ "type": "module"
46
+ }