@cocreate/utils 1.42.2 → 1.44.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/.github/FUNDING.yml +3 -0
- package/.github/workflows/automated.yml +56 -0
- package/.github/workflows/manual.yml +43 -0
- package/CHANGELOG.md +2125 -0
- package/CoCreate.config.js +23 -0
- package/demo/index.html +23 -0
- package/docs/index.html +331 -0
- package/package.json +11 -29
- package/prettier.config.js +16 -0
- package/release.config.js +30 -0
- package/src/dataQuery.js +1 -0
- package/src/index.js +90 -70
- package/src/operators.ast.js +287 -0
- package/src/operators.js +450 -89
- package/src/operators.v1.js +687 -0
- package/src/queryElements.js +7 -9
- package/webpack.config.js +65 -0
- package/dist/cjs/ObjectId.js +0 -54
- package/dist/cjs/attributes.js +0 -64
- package/dist/cjs/checkValue.js +0 -26
- package/dist/cjs/clickedElement.js +0 -48
- package/dist/cjs/core.js +0 -33
- package/dist/cjs/createUpdate.js +0 -188
- package/dist/cjs/cssPath.js +0 -60
- package/dist/cjs/dataQuery.js +0 -280
- package/dist/cjs/dom.js +0 -29
- package/dist/cjs/domParser.js +0 -44
- package/dist/cjs/dotNotationToObject.js +0 -103
- package/dist/cjs/escapeHtml.js +0 -25
- package/dist/cjs/getRelativePath.js +0 -39
- package/dist/cjs/getValueFromObject.js +0 -41
- package/dist/cjs/index.js +0 -112
- package/dist/cjs/init-browser.js +0 -4
- package/dist/cjs/isValidDate.js +0 -32
- package/dist/cjs/objectToDotNotation.js +0 -53
- package/dist/cjs/objectToSearchParams.js +0 -42
- package/dist/cjs/operators copy.js +0 -562
- package/dist/cjs/operators.js +0 -480
- package/dist/cjs/parseTextToHtml.js +0 -27
- package/dist/cjs/queryElements.js +0 -155
- package/dist/cjs/safeParse.js +0 -169
- package/dist/cjs/uid.js +0 -34
- package/dist/esm/ObjectId.js +0 -35
- package/dist/esm/attributes.js +0 -45
- package/dist/esm/checkValue.js +0 -7
- package/dist/esm/clickedElement.js +0 -29
- package/dist/esm/core.js +0 -14
- package/dist/esm/createUpdate.js +0 -185
- package/dist/esm/cssPath.js +0 -41
- package/dist/esm/dataQuery.js +0 -261
- package/dist/esm/dom.js +0 -10
- package/dist/esm/domParser.js +0 -25
- package/dist/esm/dotNotationToObject.js +0 -84
- package/dist/esm/escapeHtml.js +0 -6
- package/dist/esm/getRelativePath.js +0 -20
- package/dist/esm/getValueFromObject.js +0 -22
- package/dist/esm/index.js +0 -93
- package/dist/esm/init-browser.js +0 -4
- package/dist/esm/isValidDate.js +0 -13
- package/dist/esm/objectToDotNotation.js +0 -34
- package/dist/esm/objectToSearchParams.js +0 -23
- package/dist/esm/operators copy.js +0 -543
- package/dist/esm/operators.js +0 -461
- package/dist/esm/package.json +0 -3
- package/dist/esm/parseTextToHtml.js +0 -8
- package/dist/esm/queryElements.js +0 -136
- package/dist/esm/safeParse.js +0 -150
- package/dist/esm/uid.js +0 -15
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2026 CoCreate and Contributors.
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU Affero General Public License as published
|
|
6
|
+
* by the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
********************************************************************************/
|
|
18
|
+
|
|
19
|
+
import { getValueFromObject } from "./getValueFromObject.js";
|
|
20
|
+
import { queryElements } from "./queryElements.js";
|
|
21
|
+
|
|
22
|
+
const IsomorphicGlobals = {
|
|
23
|
+
Math,
|
|
24
|
+
Number,
|
|
25
|
+
String,
|
|
26
|
+
Boolean,
|
|
27
|
+
Date,
|
|
28
|
+
JSON,
|
|
29
|
+
Array,
|
|
30
|
+
Object,
|
|
31
|
+
parseInt,
|
|
32
|
+
parseFloat,
|
|
33
|
+
encodeURIComponent,
|
|
34
|
+
decodeURIComponent,
|
|
35
|
+
btoa: (str) => {
|
|
36
|
+
if (typeof btoa === 'function') return btoa(String(str));
|
|
37
|
+
return Buffer.from(String(str)).toString("base64");
|
|
38
|
+
},
|
|
39
|
+
atob: (b64) => {
|
|
40
|
+
if (typeof atob === 'function') return atob(b64);
|
|
41
|
+
return Buffer.from(String(b64), "base64").toString("utf-8");
|
|
42
|
+
},
|
|
43
|
+
concat: (...args) => args.flat().map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(''),
|
|
44
|
+
|
|
45
|
+
// Core Asynchronous Flow Control Operators
|
|
46
|
+
await: {
|
|
47
|
+
all: async (promises) => Promise.all(promises),
|
|
48
|
+
any: async (promises) => Promise.any(promises),
|
|
49
|
+
race: async (promises) => Promise.race(promises),
|
|
50
|
+
allSettled: async (promises) => Promise.allSettled(promises),
|
|
51
|
+
delay: (ms) => new Promise(resolve => setTimeout(resolve, Number(ms) || 0))
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const BrowserGlobals = {
|
|
56
|
+
get $organization_id() { return typeof localStorage !== 'undefined' ? localStorage.getItem("organization_id") : ""; },
|
|
57
|
+
get $user_id() { return typeof localStorage !== 'undefined' ? localStorage.getItem("user_id") : ""; },
|
|
58
|
+
get $client_id() { return typeof localStorage !== 'undefined' ? localStorage.getItem("clientId") : ""; },
|
|
59
|
+
get $session_id() { return typeof localStorage !== 'undefined' ? localStorage.getItem("session_id") : ""; },
|
|
60
|
+
get $innerWidth() { return typeof window !== 'undefined' ? window.innerWidth : 0; },
|
|
61
|
+
get $innerHeight() { return typeof window !== 'undefined' ? window.innerHeight : 0; },
|
|
62
|
+
get $href() { return typeof window !== 'undefined' ? window.location.href.replace(/\/$/, "") : ""; },
|
|
63
|
+
get $origin() { return typeof window !== 'undefined' ? window.location.origin : ""; },
|
|
64
|
+
get $protocol() { return typeof window !== 'undefined' ? window.location.protocol : ""; },
|
|
65
|
+
get $hostname() { return typeof window !== 'undefined' ? window.location.hostname : ""; },
|
|
66
|
+
get $host() { return typeof window !== 'undefined' ? window.location.host : ""; },
|
|
67
|
+
get $port() { return typeof window !== 'undefined' ? window.location.port : ""; },
|
|
68
|
+
get $pathname() { return typeof window !== 'undefined' ? window.location.pathname.replace(/\/$/, "") : ""; },
|
|
69
|
+
get $hash() { return typeof window !== 'undefined' ? window.location.hash : ""; },
|
|
70
|
+
get $subdomain() {
|
|
71
|
+
if (typeof window === 'undefined') return "";
|
|
72
|
+
const parts = window.location.hostname.split('.');
|
|
73
|
+
return parts.length > 2 ? parts[0] : "";
|
|
74
|
+
},
|
|
75
|
+
get $relativePath() {
|
|
76
|
+
if (typeof window === 'undefined') return "./";
|
|
77
|
+
const currentPath = window.location.pathname.replace(/\/[^\/]*$/, "");
|
|
78
|
+
const depth = currentPath.split("/").filter(Boolean).length;
|
|
79
|
+
return depth > 0 ? "../".repeat(depth) : "./";
|
|
80
|
+
},
|
|
81
|
+
get $path() {
|
|
82
|
+
if (typeof window === 'undefined') return "";
|
|
83
|
+
let path = window.location.pathname;
|
|
84
|
+
if (path.split("/").pop().includes(".")) path = path.replace(/\/[^\/]+$/, "/");
|
|
85
|
+
return path === "/" ? "" : path;
|
|
86
|
+
},
|
|
87
|
+
$true: () => true,
|
|
88
|
+
$false: () => false,
|
|
89
|
+
$parse: (value = "") => {
|
|
90
|
+
try { return JSON.parse(value); } catch (e) { return value; }
|
|
91
|
+
},
|
|
92
|
+
$query: function(selector) {
|
|
93
|
+
if (typeof document === 'undefined') return undefined;
|
|
94
|
+
let element = this?.this || this?.element || null;
|
|
95
|
+
if (typeof selector === 'string') {
|
|
96
|
+
selector = selector.trim().replace(/^['"]|['"]$/g, '');
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const results = queryElements({ element, selector });
|
|
100
|
+
return results && results.length > 0 ? results[0] : undefined;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.warn(`[AST Engine] Invalid $query selector => "${selector}"`, error);
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
$queryAll: function(selector) {
|
|
107
|
+
if (typeof document === 'undefined') return [];
|
|
108
|
+
let element = this?.this || this?.element || null;
|
|
109
|
+
if (typeof selector === 'string') {
|
|
110
|
+
selector = selector.trim().replace(/^['"]|['"]$/g, '');
|
|
111
|
+
if (selector.includes('$document')) return [];
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const results = queryElements({ element, selector });
|
|
115
|
+
return results ? Array.from(results) : [];
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn(`[AST Engine] Invalid $queryAll selector => "${selector}"`, error);
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const getSandboxScope = (context) => {
|
|
124
|
+
const isBrowser = typeof window !== 'undefined';
|
|
125
|
+
return {
|
|
126
|
+
...IsomorphicGlobals,
|
|
127
|
+
...(isBrowser ? BrowserGlobals : {}),
|
|
128
|
+
...context
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Universal Stateless AST Operator Engine Executor.
|
|
134
|
+
* Directly imported and run symmetrically across browser and node files.
|
|
135
|
+
*
|
|
136
|
+
* @param {Object} context - Transient execution state (element, data, event, custom refs)
|
|
137
|
+
* @param {Any} execute - The JSON AST tree to interpret
|
|
138
|
+
*/
|
|
139
|
+
export async function processOperators(context, execute) {
|
|
140
|
+
if (execute instanceof Promise) {
|
|
141
|
+
execute = await execute;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (Array.isArray(execute)) {
|
|
145
|
+
const evaluatedArray = [];
|
|
146
|
+
for (let i = 0; i < execute.length; i++) {
|
|
147
|
+
evaluatedArray[i] = await processOperators(context, execute[i]);
|
|
148
|
+
}
|
|
149
|
+
return evaluatedArray;
|
|
150
|
+
} else if (typeof execute === "object" && execute !== null) {
|
|
151
|
+
const keys = Object.keys(execute);
|
|
152
|
+
|
|
153
|
+
// Match operators starting with "$" except basic structural operators
|
|
154
|
+
const operatorKey = keys.find(k => k.startsWith("$") && !["$array", "$filter", "$storage", "$database"].includes(k));
|
|
155
|
+
|
|
156
|
+
if (operatorKey && keys.length === 1) {
|
|
157
|
+
return await executeOperator(context, operatorKey, execute[operatorKey]);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const evaluatedObject = {};
|
|
161
|
+
for (const key of keys) {
|
|
162
|
+
let finalKey = key;
|
|
163
|
+
|
|
164
|
+
if (key.startsWith("$") && !["$array", "$filter", "$storage", "$database"].includes(key)) {
|
|
165
|
+
const resolvedKey = await executeOperator(context, key);
|
|
166
|
+
if (typeof resolvedKey === "string" || typeof resolvedKey === "number") {
|
|
167
|
+
finalKey = String(resolvedKey);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let finalValue = execute[key];
|
|
172
|
+
if (typeof finalValue === "string" && finalValue.startsWith("$") && !["$array", "$filter", "$storage", "$database"].includes(finalValue)) {
|
|
173
|
+
finalValue = await executeOperator(context, finalValue);
|
|
174
|
+
} else if (Array.isArray(finalValue) || (typeof finalValue === "object" && finalValue !== null)) {
|
|
175
|
+
finalValue = await processOperators(context, finalValue);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
evaluatedObject[finalKey] = finalValue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return evaluatedObject;
|
|
182
|
+
} else if (typeof execute === "string" && execute.startsWith("$") && !["$array", "$filter", "$storage", "$database"].includes(execute)) {
|
|
183
|
+
return await executeOperator(context, execute);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return execute;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function executeOperator(context, operator, args) {
|
|
190
|
+
const localContext = {
|
|
191
|
+
state: {},
|
|
192
|
+
...context
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Evaluate basic context property lookups
|
|
196
|
+
if (args === undefined) {
|
|
197
|
+
if (operator.startsWith("$state.")) {
|
|
198
|
+
return getValueFromObject(localContext.state, operator.substring(7));
|
|
199
|
+
} else if (operator === "$state") {
|
|
200
|
+
return localContext.state;
|
|
201
|
+
} else if (operator.startsWith("$data.")) {
|
|
202
|
+
return getValueFromObject(localContext.data, operator.substring(6));
|
|
203
|
+
} else if (operator === "$data") {
|
|
204
|
+
return localContext.data;
|
|
205
|
+
} else if (operator.startsWith("$event.")) {
|
|
206
|
+
return getValueFromObject(localContext.event, operator.substring(7));
|
|
207
|
+
} else if (operator === "$event") {
|
|
208
|
+
return localContext.event;
|
|
209
|
+
} else if (operator.startsWith("$request.")) {
|
|
210
|
+
return getValueFromObject(localContext.request, operator.substring(9));
|
|
211
|
+
} else if (operator === "$request") {
|
|
212
|
+
return localContext.request;
|
|
213
|
+
} else if (operator.startsWith("$header.")) {
|
|
214
|
+
const headerKey = operator.substring(8).toLowerCase();
|
|
215
|
+
return localContext.request?.headers?.[headerKey];
|
|
216
|
+
} else if (operator === "$rawBody") {
|
|
217
|
+
return localContext.rawBody;
|
|
218
|
+
} else if (operator === "$this") {
|
|
219
|
+
return localContext.this || localContext.element;
|
|
220
|
+
} else if (operator === "$value") {
|
|
221
|
+
const el = localContext.this || localContext.element;
|
|
222
|
+
return el && typeof el.getValue === 'function' ? el.getValue() : "";
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let isExplicitNew = false;
|
|
227
|
+
let cleanPath = operator.startsWith("$") ? operator.substring(1) : operator;
|
|
228
|
+
|
|
229
|
+
if (cleanPath.startsWith("new.")) {
|
|
230
|
+
isExplicitNew = true;
|
|
231
|
+
cleanPath = cleanPath.substring(4);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const parts = cleanPath.split('.');
|
|
235
|
+
const SandboxScope = getSandboxScope(localContext);
|
|
236
|
+
|
|
237
|
+
let target = SandboxScope[parts[0]];
|
|
238
|
+
let parentContext = SandboxScope;
|
|
239
|
+
|
|
240
|
+
if (target !== undefined) {
|
|
241
|
+
for (let i = 1; i < parts.length; i++) {
|
|
242
|
+
parentContext = target;
|
|
243
|
+
target = target[parts[i]];
|
|
244
|
+
if (target === undefined) break;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (typeof target === 'function') {
|
|
248
|
+
let argsArray = [];
|
|
249
|
+
if (args !== undefined) {
|
|
250
|
+
// Intercept human-friendly parameter keywords ($args, $arguments)
|
|
251
|
+
if (typeof args === 'object' && args !== null && (args.$args !== undefined || args.$arguments !== undefined)) {
|
|
252
|
+
const explicitArgs = args.$args !== undefined ? args.$args : args.$arguments;
|
|
253
|
+
|
|
254
|
+
if (Array.isArray(explicitArgs)) {
|
|
255
|
+
argsArray = [];
|
|
256
|
+
for (let i = 0; i < explicitArgs.length; i++) {
|
|
257
|
+
argsArray.push(await processOperators(localContext, explicitArgs[i]));
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
const evaluatedSingle = await processOperators(localContext, explicitArgs);
|
|
261
|
+
argsArray = [evaluatedSingle];
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
const evaluatedSingle = await processOperators(localContext, args);
|
|
265
|
+
argsArray = [evaluatedSingle];
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const isEs6Class = /^\s*class\s+/.test(target.toString());
|
|
270
|
+
|
|
271
|
+
if (isExplicitNew || isEs6Class) {
|
|
272
|
+
return new target(...argsArray);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Implicit auto-await globally executes any resolved function natively
|
|
276
|
+
return await target.apply(localContext, argsArray);
|
|
277
|
+
} else if (target !== undefined) {
|
|
278
|
+
return target;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return operator;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export { processOperators as processOperatorsAsync }; // Alias for async usage
|
|
286
|
+
export const customOperators = {}; // Stateless fallback placeholder registry
|
|
287
|
+
export default processOperators;
|