data-primals-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/src/core.js ADDED
@@ -0,0 +1,340 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import crypto from "node:crypto";
4
+
5
+ export const sleep = (ms = 1000) =>
6
+ new Promise((resolve) => setTimeout(resolve, ms));
7
+
8
+ export function escapeRegex(string) {
9
+ return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
10
+ }
11
+
12
+ export const isDate = dt => String(new Date(dt)) !== 'Invalid Date'
13
+
14
+ export function debounce(callback, delay=300){
15
+ var timer;
16
+ return function(){
17
+ var args = arguments;
18
+ var context = this;
19
+ clearTimeout(timer);
20
+ timer = setTimeout(function(){
21
+ callback.apply(context, args);
22
+ }, delay)
23
+ }
24
+ }
25
+
26
+ export function uuidv4() {
27
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
28
+ (+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
29
+ );
30
+ }
31
+
32
+ export function cssProps(cssString) {
33
+ if (!cssString) return {};
34
+
35
+ const style = {};
36
+ const declarations = cssString.split(';');
37
+
38
+ declarations.forEach(declaration => {
39
+ const trimmed = declaration.trim();
40
+ if (!trimmed) return;
41
+
42
+ const colonIndex = trimmed.indexOf(':');
43
+ if (colonIndex === -1) return;
44
+
45
+ let property = trimmed.slice(0, colonIndex).trim();
46
+ const value = trimmed.slice(colonIndex + 1).trim();
47
+
48
+ // Convert kebab-case to camelCase
49
+ if (property.includes('-')) {
50
+ property = property.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
51
+ }
52
+
53
+ style[property] = value;
54
+ });
55
+
56
+ return style;
57
+ }
58
+
59
+
60
+ export function removeDir(dirPath) {
61
+ const dirContents = fs.readdirSync(dirPath); // List dir content
62
+
63
+ for (const fileOrDirPath of dirContents) {
64
+ try {
65
+ // Get Full path
66
+ const fullPath = path.join(dirPath, fileOrDirPath);
67
+ const stat = fs.statSync(fullPath);
68
+ if (stat.isDirectory()) {
69
+ // It's a sub directory
70
+ if (fs.readdirSync(fullPath).length) removeDir(fullPath);
71
+ // If the dir is not empty then remove it's contents too(recursively)
72
+ fs.rmdirSync(fullPath);
73
+ } else fs.unlinkSync(fullPath); // It's a file
74
+ } catch (ex) {
75
+ console.error(ex.message);
76
+ }
77
+ }
78
+
79
+ }
80
+
81
+ export const wordWrap = (str, max, br = '\n') => str.replace(
82
+ new RegExp(`(?![^\\n]{1,${max}}$)([^\\n]{1,${max}})\\s`, 'g'), `$1${br}`
83
+ );
84
+
85
+ export const getObjectHash = (obj, uniqueFields = null, key = "") => {
86
+ let str = "";
87
+ const keysToProcess = Object.keys(obj).sort(); // Trier les clés pour la cohérence
88
+
89
+ keysToProcess.forEach(k1 => {
90
+ const v = obj[k1];
91
+ if (v !== undefined) { // Ignorer les clés avec des valeurs undefined
92
+ // Simplification de la logique: on inclut soit les champs uniques, soit tous les champs.
93
+ // La sérialisation est la même dans les deux cas pour un champ donné.
94
+ if (uniqueFields === null || uniqueFields.length === 0 || uniqueFields.includes(k1)) {
95
+ try {
96
+ // Utiliser JSON.stringify avec un replacer pour gérer plus de types si nécessaire,
97
+ // ou simplement stringify directement. Attention aux types non sérialisables.
98
+ str += k1 + ':' + JSON.stringify(v) + ';'; // Inclure clé + valeur sérialisée
99
+ } catch (e) {
100
+ // Gérer les erreurs de sérialisation (ex: objets circulaires)
101
+ console.warn(`Could not stringify value for key ${k1} in getObjectHash`, e);
102
+ str += k1 + ':[unserializable];';
103
+ }
104
+ }
105
+ }
106
+ });
107
+
108
+ const buffer = str + key; // Ajouter la clé optionnelle à la fin
109
+
110
+ // Utiliser cyrb53 pour le hachage final
111
+ return cyrb53(buffer);
112
+ };
113
+
114
+ export function isPathRelativeTo(dir, parent) {
115
+ const relative = path.relative(parent, dir);
116
+ return relative && !relative.startsWith('..') && !path.isAbsolute(relative);
117
+ }
118
+
119
+ /**
120
+ * Ensures the value is a valid GUID
121
+ * @param value string value
122
+ */
123
+ export function isGUID(value) {
124
+ return typeof(value) === 'string' && value.match(/^[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}$/);
125
+ }
126
+
127
+ export function isPlainObject(obj) {
128
+ return typeof obj === 'object' && obj !== null;
129
+ }
130
+
131
+ export function escapeRegExp(string) {
132
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
133
+ }
134
+
135
+ export function shuffle(array) {
136
+ let currentIndex = array.length;
137
+
138
+ // While there remain elements to shuffle...
139
+ while (currentIndex != 0) {
140
+
141
+ // Pick a remaining element...
142
+ let randomIndex = Math.floor(Math.random() * currentIndex);
143
+ currentIndex--;
144
+
145
+ // And swap it with the current element.
146
+ [array[currentIndex], array[randomIndex]] = [
147
+ array[randomIndex], array[currentIndex]];
148
+ }
149
+ }
150
+
151
+ function sfc32(a, b, c, d) {
152
+ a |= 0; b |= 0; c |= 0; d |= 0;
153
+ let t = (a + b | 0) + d | 0;
154
+ d = d + 1 | 0;
155
+ a = b ^ b >>> 9;
156
+ b = c + (c << 3) | 0;
157
+ c = (c << 21 | c >>> 11);
158
+ c = c + t | 0;
159
+ return (t >>> 0) / 4294967296;
160
+ }
161
+
162
+ let seed = 0;
163
+ export const setSeed = (s)=>{
164
+ seed = s;
165
+ }
166
+ function splitmix32(a) {
167
+ a |= 0;
168
+ a = a + 0x9e3779b9 | 0;
169
+ let t = a ^ a >>> 16;
170
+ t = Math.imul(t, 0x21f0aaad);
171
+ t = t ^ t >>> 15;
172
+ t = Math.imul(t, 0x735a2d97);
173
+ return ((t = t ^ t >>> 15) >>> 0) / 4294967296;
174
+ }
175
+
176
+ export const getRand = () =>splitmix32(seed);
177
+
178
+ export const getRandom = (minInclusive,maxInclusive) => {
179
+ return Math.floor(Math.random() * (maxInclusive - minInclusive + 1) + minInclusive);
180
+ };
181
+
182
+ export function randomDate(start, end) {
183
+ return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
184
+ }
185
+ export function isLightColor(color) {
186
+ if( !color )
187
+ return true;
188
+ const hex = color.replace('#', '');
189
+ const c_r = parseInt(hex.substr(0, 2), 16);
190
+ const c_g = parseInt(hex.substr(2, 2), 16);
191
+ const c_b = parseInt(hex.substr(4, 2), 16);
192
+ const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
193
+ return brightness > 155;
194
+ }
195
+
196
+ // Mettez cette fonction au début du fichier DataEditor.jsx ou dans un fichier utilitaire importé
197
+ export const tryParseJson = (jsonString) => {
198
+ if (!jsonString || typeof jsonString !== 'string') {
199
+ return null; // Retourne null si la chaîne est vide, null, ou pas une chaîne
200
+ }
201
+ try {
202
+ // Tenter de parser la chaîne JSON
203
+ const parsed = JSON.parse(jsonString);
204
+ // S'assurer que c'est un objet ou null (pas un simple nombre, string, etc.)
205
+ return (typeof parsed === 'object' || parsed === null) ? parsed : null;
206
+ } catch (e) {
207
+ console.error("Failed to parse condition JSON:", e, jsonString);
208
+ return null; // Retourne null en cas d'erreur de parsing
209
+ }
210
+ };
211
+
212
+ export function isIsoDate(str) {
213
+ if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) return false;
214
+ const d = new Date(str);
215
+ return !isNaN(d.getTime()) && d.toISOString()===str; // valid date
216
+ }
217
+
218
+
219
+ Math.seed = function(s) {
220
+ return function() {
221
+ s = Math.sin(s) * 10000; return s - Math.floor(s);
222
+ };
223
+ };
224
+
225
+ const cyrb53 = (str, seed = 0) => {
226
+ let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
227
+ for(let i = 0, ch; i < str.length; i++) {
228
+ ch = str.charCodeAt(i);
229
+ h1 = Math.imul(h1 ^ ch, 2654435761);
230
+ h2 = Math.imul(h2 ^ ch, 1597334677);
231
+ }
232
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
233
+ h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
234
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
235
+ h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
236
+
237
+ return 4294967296 * (2097151 & h2) + (h1 >>> 0);
238
+ };
239
+
240
+ String.prototype.hashCode = function() {
241
+ return cyrb53(this);
242
+ }
243
+
244
+ export function random(min, max) {
245
+ min = Math.ceil(min);
246
+ max = Math.floor(max);
247
+ return Math.floor(Math.random() * (max - min + 1)) + min;
248
+ }
249
+
250
+
251
+ let triggers = {};
252
+ export const event_trigger = (name, ...params) => {
253
+ //console.log('Triggering raw event "' + name + '"');
254
+ let ret = false;
255
+ if (Array.isArray(triggers[name])) {
256
+ triggers[name].forEach((t) => {
257
+ const res = t.callback(...params);
258
+ if (Array.isArray(res)) {
259
+ if (!Array.isArray(ret)) ret = [];
260
+ ret = ret.concat(res);
261
+ } else if (typeof res === "string") {
262
+ if (typeof ret !== "string") ret = "";
263
+ ret += res;
264
+ } else if (typeof res === "number") {
265
+ if (typeof ret !== "number") ret = 0;
266
+ ret += res;
267
+ } else if (typeof res === "boolean") {
268
+ if (typeof ret !== "boolean") ret = true;
269
+ ret = res && ret;
270
+ } else {
271
+ ret = res || ret;
272
+ }
273
+ });
274
+ }
275
+ return ret;
276
+ };
277
+ export const event_on = (name, callback) => {
278
+ if (!Array.isArray(triggers[name])) {
279
+ triggers[name] = [];
280
+ }
281
+ triggers[name].push({ callback });
282
+ };
283
+ export const event_off = (name, callback) => {
284
+ if (callback && triggers[name]) {
285
+ triggers[name] = triggers[name].filter((f) => f.callback !== callback);
286
+ } else {
287
+ triggers[name] = undefined;
288
+ }
289
+ };
290
+
291
+
292
+ export function slugify(str) {
293
+ str = str.replace(/^\s+|\s+$/g, ''); // trim leading/trailing white space
294
+ str = str.toLowerCase(); // convert string to lowercase
295
+ str = str.replace(/[^a-z0-9 -]/g, '') // remove any non-alphanumeric characters
296
+ .replace(/\s+/g, '-') // replace spaces with hyphens
297
+ .replace(/-+/g, '-'); // remove consecutive hyphens
298
+ return str;
299
+ }
300
+
301
+ // resource : https://stackoverflow.com/questions/190852/how-can-i-get-file-extensions-with-javascript
302
+ export function getFileExtension(fname) {
303
+ return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2);
304
+ }
305
+
306
+ export function object_equals( x, y ) {
307
+ if ( x === y ) return true;
308
+ // if both x and y are null or undefined and exactly the same
309
+
310
+ if ( ! ( x instanceof Object ) || ! ( y instanceof Object ) ) return false;
311
+ // if they are not strictly equal, they both need to be Objects
312
+
313
+ if ( x.constructor !== y.constructor ) return false;
314
+ // they must have the exact same prototype chain, the closest we can do is
315
+ // test there constructor.
316
+
317
+ for ( var p in x ) {
318
+ if ( ! x.hasOwnProperty( p ) ) continue;
319
+ // other properties were tested using x.constructor === y.constructor
320
+
321
+ if ( ! y.hasOwnProperty( p ) ) return false;
322
+ // allows to compare x[ p ] and y[ p ] when set to undefined
323
+
324
+ if ( x[ p ] === y[ p ] ) continue;
325
+ // if they have the same strict value or identity then they are equal
326
+
327
+ if ( typeof( x[ p ] ) !== "object" ) return false;
328
+ // Numbers, Strings, Functions, Booleans must be strictly equal
329
+
330
+ if ( ! object_equals( x[ p ], y[ p ] ) ) return false;
331
+ // Objects and Arrays must be tested recursively
332
+ }
333
+
334
+ for ( p in y )
335
+ if ( y.hasOwnProperty( p ) && ! x.hasOwnProperty( p ) )
336
+ return false;
337
+ // allows x[ p ] to be set to undefined
338
+
339
+ return true;
340
+ }