@dyrected/core 2.9.0 → 2.10.1
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/dist/{app-config-gEQJFvnN.d.cts → app-config-BLC7WoyL.d.cts} +439 -44
- package/dist/{app-config-gEQJFvnN.d.ts → app-config-BLC7WoyL.d.ts} +439 -44
- package/dist/{chunk-XRIONGRY.js → chunk-H7DVVW2P.js} +115 -30
- package/dist/index.cjs +526 -67
- package/dist/index.d.cts +401 -86
- package/dist/index.d.ts +401 -86
- package/dist/index.js +408 -38
- package/dist/server.cjs +160 -39
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +45 -10
- package/dist/{where-sanitizer-3MNFMYA2.js → where-sanitizer-47QPJQ6O.js} +3 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -101,7 +101,7 @@ import {
|
|
|
101
101
|
validatePreviewUrlExpression,
|
|
102
102
|
wordCount,
|
|
103
103
|
workflowCapabilities
|
|
104
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-H7DVVW2P.js";
|
|
105
105
|
import "./chunk-JSBRDJBE.js";
|
|
106
106
|
|
|
107
107
|
// src/types/workflows.ts
|
|
@@ -114,44 +114,17 @@ var LIFECYCLE_EVENT_NAMES = [
|
|
|
114
114
|
|
|
115
115
|
// src/types/views.ts
|
|
116
116
|
function defineView(config) {
|
|
117
|
-
return
|
|
118
|
-
slug: config.slug,
|
|
119
|
-
label: config.label,
|
|
120
|
-
icon: config.icon,
|
|
121
|
-
layout: config.layout ?? "table",
|
|
122
|
-
filter: config.filter,
|
|
123
|
-
groupBy: config.groupBy,
|
|
124
|
-
dateField: config.dateField,
|
|
125
|
-
startDateField: config.startDateField,
|
|
126
|
-
endDateField: config.endDateField,
|
|
127
|
-
columns: config.columns,
|
|
128
|
-
sort: config.sort,
|
|
129
|
-
actions: config.actions,
|
|
130
|
-
features: config.features,
|
|
131
|
-
actionOrder: config.actionOrder,
|
|
132
|
-
metrics: config.metrics,
|
|
133
|
-
access: config.access
|
|
134
|
-
};
|
|
117
|
+
return config;
|
|
135
118
|
}
|
|
136
119
|
function defineAction(config) {
|
|
137
|
-
return
|
|
138
|
-
name: config.name,
|
|
139
|
-
label: config.label,
|
|
140
|
-
icon: config.icon,
|
|
141
|
-
type: config.type ?? "row",
|
|
142
|
-
confirm: config.confirm,
|
|
143
|
-
fields: config.fields,
|
|
144
|
-
mutation: config.mutation,
|
|
145
|
-
handler: config.handler,
|
|
146
|
-
access: config.access
|
|
147
|
-
};
|
|
120
|
+
return config;
|
|
148
121
|
}
|
|
149
122
|
|
|
150
123
|
// src/utils/parse-where.ts
|
|
151
124
|
function assertNever(op, context) {
|
|
152
125
|
throw new Error(`[dyrected/core] Unhandled where operator "${op}" in ${context}`);
|
|
153
126
|
}
|
|
154
|
-
function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = "LIKE") {
|
|
127
|
+
function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = placeholder === "pg" ? "ILIKE" : "LIKE") {
|
|
155
128
|
const params = [];
|
|
156
129
|
let pgIndex = 1;
|
|
157
130
|
function next() {
|
|
@@ -162,8 +135,16 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = "L
|
|
|
162
135
|
}
|
|
163
136
|
function buildOperator(field, value) {
|
|
164
137
|
const c = col(field);
|
|
138
|
+
const isJsonExtract = c.startsWith("data->>") || c.startsWith("json_extract(") || c.startsWith("JSON_UNQUOTE(");
|
|
165
139
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
166
|
-
|
|
140
|
+
if (value === null) {
|
|
141
|
+
return `${c} IS NULL`;
|
|
142
|
+
}
|
|
143
|
+
if (value === "" && placeholder === "pg") {
|
|
144
|
+
params.push("");
|
|
145
|
+
return `(${c})::text = ${next()}`;
|
|
146
|
+
}
|
|
147
|
+
params.push(typeof value === "boolean" && isJsonExtract ? String(value) : value);
|
|
167
148
|
return `${c} = ${next()}`;
|
|
168
149
|
}
|
|
169
150
|
const entries = Object.entries(value);
|
|
@@ -174,18 +155,63 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = "L
|
|
|
174
155
|
return buildSingleOp(c, op, operand);
|
|
175
156
|
}
|
|
176
157
|
function buildSingleOp(c, op, operand) {
|
|
158
|
+
const isJsonExtract = c.startsWith("data->>") || c.startsWith("json_extract(") || c.startsWith("JSON_UNQUOTE(");
|
|
177
159
|
switch (op) {
|
|
178
160
|
case "equals":
|
|
179
|
-
|
|
161
|
+
if (operand === null) {
|
|
162
|
+
return `${c} IS NULL`;
|
|
163
|
+
}
|
|
164
|
+
if (operand === "" && placeholder === "pg") {
|
|
165
|
+
params.push("");
|
|
166
|
+
return `(${c})::text = ${next()}`;
|
|
167
|
+
}
|
|
168
|
+
if (typeof operand === "boolean") {
|
|
169
|
+
if (placeholder === "?") {
|
|
170
|
+
params.push(operand ? 1 : 0);
|
|
171
|
+
} else if (isJsonExtract) {
|
|
172
|
+
params.push(String(operand));
|
|
173
|
+
} else {
|
|
174
|
+
params.push(operand);
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
params.push(operand);
|
|
178
|
+
}
|
|
180
179
|
return `${c} = ${next()}`;
|
|
181
180
|
case "not_equals":
|
|
182
|
-
|
|
181
|
+
if (operand === null) {
|
|
182
|
+
return `${c} IS NOT NULL`;
|
|
183
|
+
}
|
|
184
|
+
if (operand === "" && placeholder === "pg") {
|
|
185
|
+
params.push("");
|
|
186
|
+
return `(${c})::text != ${next()}`;
|
|
187
|
+
}
|
|
188
|
+
if (typeof operand === "boolean") {
|
|
189
|
+
if (placeholder === "?") {
|
|
190
|
+
params.push(operand ? 1 : 0);
|
|
191
|
+
} else if (isJsonExtract) {
|
|
192
|
+
params.push(String(operand));
|
|
193
|
+
} else {
|
|
194
|
+
params.push(operand);
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
params.push(operand);
|
|
198
|
+
}
|
|
183
199
|
return `${c} != ${next()}`;
|
|
184
200
|
case "in": {
|
|
185
201
|
const vals = Array.isArray(operand) ? operand : [operand];
|
|
186
202
|
if (vals.length === 0) return "1=0";
|
|
187
203
|
const placeholders = vals.map((v) => {
|
|
188
|
-
|
|
204
|
+
if (typeof v === "boolean") {
|
|
205
|
+
if (placeholder === "?") {
|
|
206
|
+
params.push(v ? 1 : 0);
|
|
207
|
+
} else if (isJsonExtract) {
|
|
208
|
+
params.push(String(v));
|
|
209
|
+
} else {
|
|
210
|
+
params.push(v);
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
params.push(v);
|
|
214
|
+
}
|
|
189
215
|
return next();
|
|
190
216
|
});
|
|
191
217
|
return `${c} IN (${placeholders.join(", ")})`;
|
|
@@ -194,7 +220,7 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = "L
|
|
|
194
220
|
const vals = Array.isArray(operand) ? operand : [operand];
|
|
195
221
|
if (vals.length === 0) return "1=1";
|
|
196
222
|
const placeholders = vals.map((v) => {
|
|
197
|
-
params.push(typeof v === "boolean" ? String(v) : v);
|
|
223
|
+
params.push(typeof v === "boolean" && isJsonExtract ? String(v) : v);
|
|
198
224
|
return next();
|
|
199
225
|
});
|
|
200
226
|
return `${c} NOT IN (${placeholders.join(", ")})`;
|
|
@@ -220,10 +246,10 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = "L
|
|
|
220
246
|
case "contains":
|
|
221
247
|
case "like":
|
|
222
248
|
params.push(`%${operand}%`);
|
|
223
|
-
return `${c} ${likeOperator} ${next()}`;
|
|
249
|
+
return placeholder === "pg" ? `(${c})::text ${likeOperator} ${next()}` : `${c} ${likeOperator} ${next()}`;
|
|
224
250
|
case "starts_with":
|
|
225
251
|
params.push(`${operand}%`);
|
|
226
|
-
return `${c} ${likeOperator} ${next()}`;
|
|
252
|
+
return placeholder === "pg" ? `(${c})::text ${likeOperator} ${next()}` : `${c} ${likeOperator} ${next()}`;
|
|
227
253
|
case "exists":
|
|
228
254
|
return operand ? `${c} IS NOT NULL` : `${c} IS NULL`;
|
|
229
255
|
default:
|
|
@@ -363,6 +389,346 @@ function buildSqlOrderBy(sort, existingColumns, numericFields, dialect) {
|
|
|
363
389
|
}).join(", ");
|
|
364
390
|
}
|
|
365
391
|
|
|
392
|
+
// src/utils/conditions.ts
|
|
393
|
+
function formatJexlValue(v) {
|
|
394
|
+
if (v === null || v === void 0) return "null";
|
|
395
|
+
if (typeof v === "boolean" || typeof v === "number") return String(v);
|
|
396
|
+
if (typeof v === "string") {
|
|
397
|
+
if (v.startsWith("'") && v.endsWith("'") || v.startsWith('"') && v.endsWith('"') || v.includes("+") || v.includes("?") || v.includes("(") || v.includes(" ")) {
|
|
398
|
+
return v;
|
|
399
|
+
}
|
|
400
|
+
if (v.startsWith("/")) {
|
|
401
|
+
return `'${v}'`;
|
|
402
|
+
}
|
|
403
|
+
if (v === "null" || v === "true" || v === "false") {
|
|
404
|
+
return v;
|
|
405
|
+
}
|
|
406
|
+
if (/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(v)) {
|
|
407
|
+
return v;
|
|
408
|
+
}
|
|
409
|
+
return `'${v}'`;
|
|
410
|
+
}
|
|
411
|
+
return String(v);
|
|
412
|
+
}
|
|
413
|
+
var MatchBuilder = class {
|
|
414
|
+
branches = [];
|
|
415
|
+
/**
|
|
416
|
+
* Adds a conditional branch (`condition ? value : ...`).
|
|
417
|
+
*/
|
|
418
|
+
case(condition, value) {
|
|
419
|
+
this.branches.push({ condition, value });
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Final fallback value when no cases match.
|
|
424
|
+
*/
|
|
425
|
+
otherwise(fallback = "null") {
|
|
426
|
+
if (this.branches.length === 0) return formatJexlValue(fallback);
|
|
427
|
+
let expr = formatJexlValue(fallback);
|
|
428
|
+
for (let i = this.branches.length - 1; i >= 0; i--) {
|
|
429
|
+
const b = this.branches[i];
|
|
430
|
+
expr = `${b.condition} ? ${formatJexlValue(b.value)} : ${expr}`;
|
|
431
|
+
}
|
|
432
|
+
return expr;
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
var FieldConditionBuilder = class {
|
|
436
|
+
constructor(field) {
|
|
437
|
+
this.field = field;
|
|
438
|
+
}
|
|
439
|
+
field;
|
|
440
|
+
/**
|
|
441
|
+
* Generates equality condition (`field == value`).
|
|
442
|
+
*/
|
|
443
|
+
equals(value) {
|
|
444
|
+
return `${this.field} == ${JSON.stringify(value)}`;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Generates inequality condition (`field != value`).
|
|
448
|
+
*/
|
|
449
|
+
notEquals(value) {
|
|
450
|
+
return `${this.field} != ${JSON.stringify(value)}`;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Generates set membership condition (`field in [val1, val2]`).
|
|
454
|
+
*/
|
|
455
|
+
in(...values) {
|
|
456
|
+
const flat = values.flat();
|
|
457
|
+
return `${this.field} in [${flat.map((v) => JSON.stringify(v)).join(", ")}]`;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Generates inverted set membership condition (`!(field in [val1, val2])`).
|
|
461
|
+
*/
|
|
462
|
+
notIn(...values) {
|
|
463
|
+
const flat = values.flat();
|
|
464
|
+
return `!(${this.field} in [${flat.map((v) => JSON.stringify(v)).join(", ")}])`;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Generates boolean true check (`field == true`).
|
|
468
|
+
*/
|
|
469
|
+
isTrue() {
|
|
470
|
+
return `${this.field} == true`;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Generates boolean false check (`field != true`).
|
|
474
|
+
*/
|
|
475
|
+
isFalse() {
|
|
476
|
+
return `${this.field} != true`;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Checks that the field is neither null/undefined nor an empty string.
|
|
480
|
+
*/
|
|
481
|
+
notEmpty() {
|
|
482
|
+
return `${this.field} != null && ${this.field} != ''`;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Checks that the field is null, undefined, or an empty string.
|
|
486
|
+
*/
|
|
487
|
+
isEmpty() {
|
|
488
|
+
return `${this.field} == null || ${this.field} == ''`;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Numerical greater than (`field > num`).
|
|
492
|
+
*/
|
|
493
|
+
greaterThan(num) {
|
|
494
|
+
return `${this.field} > ${typeof num === "number" ? num : num}`;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Numerical greater than or equal (`field >= num`).
|
|
498
|
+
*/
|
|
499
|
+
greaterThanOrEqual(num) {
|
|
500
|
+
return `${this.field} >= ${typeof num === "number" ? num : num}`;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Numerical less than (`field < num`).
|
|
504
|
+
*/
|
|
505
|
+
lessThan(num) {
|
|
506
|
+
return `${this.field} < ${typeof num === "number" ? num : num}`;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Numerical less than or equal (`field <= num`).
|
|
510
|
+
*/
|
|
511
|
+
lessThanOrEqual(num) {
|
|
512
|
+
return `${this.field} <= ${typeof num === "number" ? num : num}`;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Numerical range check (`field >= min && field <= max`).
|
|
516
|
+
*/
|
|
517
|
+
between(min2, max2) {
|
|
518
|
+
return `${this.field} >= ${min2} && ${this.field} <= ${max2}`;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* String prefix check using JEXL `startsWith(field, prefix)`.
|
|
522
|
+
*/
|
|
523
|
+
startsWith(prefix) {
|
|
524
|
+
return `startsWith(${this.field}, ${JSON.stringify(prefix)})`;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* String suffix check using JEXL `endsWith(field, suffix)`.
|
|
528
|
+
*/
|
|
529
|
+
endsWith(suffix) {
|
|
530
|
+
return `endsWith(${this.field}, ${JSON.stringify(suffix)})`;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Substring or array item check using JEXL `includes(field, item)`.
|
|
534
|
+
*/
|
|
535
|
+
contains(val) {
|
|
536
|
+
return `includes(${this.field}, ${JSON.stringify(val)})`;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Checks if array/string length exceeds a threshold.
|
|
540
|
+
*/
|
|
541
|
+
hasLengthGreaterThan(length2) {
|
|
542
|
+
return `length(${this.field}) > ${length2}`;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Checks if array/string length is at least a threshold.
|
|
546
|
+
*/
|
|
547
|
+
hasLengthAtLeast(length2) {
|
|
548
|
+
return `length(${this.field}) >= ${length2}`;
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
function createWhen() {
|
|
552
|
+
const whenFn = ((fieldName) => new FieldConditionBuilder(fieldName));
|
|
553
|
+
whenFn.user = (userProp) => new FieldConditionBuilder(`user.${userProp}`);
|
|
554
|
+
whenFn.sibling = (siblingProp) => new FieldConditionBuilder(`siblingData.${siblingProp}`);
|
|
555
|
+
whenFn.concat = (...parts) => {
|
|
556
|
+
if (parts.length === 0) return "''";
|
|
557
|
+
return parts.map((p) => formatJexlValue(p)).join(" + ");
|
|
558
|
+
};
|
|
559
|
+
whenFn.slugify = (field) => `slugify(${field})`;
|
|
560
|
+
whenFn.lower = (field) => `lower(${field})`;
|
|
561
|
+
whenFn.upper = (field) => `upper(${field})`;
|
|
562
|
+
whenFn.trim = (field) => `trim(${field})`;
|
|
563
|
+
whenFn.access = {
|
|
564
|
+
isOwner: (ownerField = "author") => {
|
|
565
|
+
return `${ownerField} == user.id || ${ownerField}.id == user.id`;
|
|
566
|
+
},
|
|
567
|
+
isAdmin: () => {
|
|
568
|
+
return "user.role == 'admin' || (user.roles != null && 'admin' in user.roles)";
|
|
569
|
+
},
|
|
570
|
+
hasRole: (...roles) => {
|
|
571
|
+
return whenFn.userRole(...roles);
|
|
572
|
+
},
|
|
573
|
+
isPublishedOrAdmin: (statusField = "status") => {
|
|
574
|
+
return `${statusField} == 'published' || user.role == 'admin' || (user.roles != null && 'admin' in user.roles)`;
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
whenFn.then = (condition, ifTrue, ifFalse = "null") => {
|
|
578
|
+
return `${condition} ? ${formatJexlValue(ifTrue)} : ${formatJexlValue(ifFalse)}`;
|
|
579
|
+
};
|
|
580
|
+
whenFn.match = () => new MatchBuilder();
|
|
581
|
+
whenFn.cases = (...branches) => {
|
|
582
|
+
const builder = new MatchBuilder();
|
|
583
|
+
let fallback = "null";
|
|
584
|
+
for (const b of branches) {
|
|
585
|
+
if (Array.isArray(b)) {
|
|
586
|
+
builder.case(b[0], b[1]);
|
|
587
|
+
} else {
|
|
588
|
+
fallback = b;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return builder.otherwise(fallback);
|
|
592
|
+
};
|
|
593
|
+
whenFn.all = (...conditions) => {
|
|
594
|
+
const valid = conditions.filter(Boolean);
|
|
595
|
+
if (valid.length === 0) return "true";
|
|
596
|
+
if (valid.length === 1) return valid[0];
|
|
597
|
+
return valid.map((c) => c.includes(" ") ? `(${c})` : c).join(" && ");
|
|
598
|
+
};
|
|
599
|
+
whenFn.and = whenFn.all;
|
|
600
|
+
whenFn.any = (...conditions) => {
|
|
601
|
+
const valid = conditions.filter(Boolean);
|
|
602
|
+
if (valid.length === 0) return "true";
|
|
603
|
+
if (valid.length === 1) return valid[0];
|
|
604
|
+
return valid.map((c) => c.includes(" ") ? `(${c})` : c).join(" || ");
|
|
605
|
+
};
|
|
606
|
+
whenFn.or = whenFn.any;
|
|
607
|
+
whenFn.not = (condition) => {
|
|
608
|
+
if (!condition) return "false";
|
|
609
|
+
return `!(${condition})`;
|
|
610
|
+
};
|
|
611
|
+
whenFn.variant = (...variants) => {
|
|
612
|
+
const flat = variants.flat();
|
|
613
|
+
if (flat.length === 0) return "true";
|
|
614
|
+
if (flat.length === 1) return `variant == '${flat[0]}'`;
|
|
615
|
+
return `variant in [${flat.map((v) => `'${v}'`).join(", ")}]`;
|
|
616
|
+
};
|
|
617
|
+
whenFn.notVariant = (...variants) => {
|
|
618
|
+
const flat = variants.flat();
|
|
619
|
+
if (flat.length === 0) return "false";
|
|
620
|
+
if (flat.length === 1) return `variant != '${flat[0]}'`;
|
|
621
|
+
return `!(variant in [${flat.map((v) => `'${v}'`).join(", ")}])`;
|
|
622
|
+
};
|
|
623
|
+
whenFn.block = (...blocks) => {
|
|
624
|
+
const flat = blocks.flat();
|
|
625
|
+
if (flat.length === 0) return "true";
|
|
626
|
+
if (flat.length === 1) return `block == '${flat[0]}'`;
|
|
627
|
+
return `block in [${flat.map((b) => `'${b}'`).join(", ")}]`;
|
|
628
|
+
};
|
|
629
|
+
whenFn.notBlock = (...blocks) => {
|
|
630
|
+
const flat = blocks.flat();
|
|
631
|
+
if (flat.length === 0) return "false";
|
|
632
|
+
if (flat.length === 1) return `block != '${flat[0]}'`;
|
|
633
|
+
return `!(block in [${flat.map((b) => `'${b}'`).join(", ")}])`;
|
|
634
|
+
};
|
|
635
|
+
whenFn.fieldEquals = (field, value) => {
|
|
636
|
+
return `${field} == ${JSON.stringify(value)}`;
|
|
637
|
+
};
|
|
638
|
+
whenFn.fieldNotEquals = (field, value) => {
|
|
639
|
+
return `${field} != ${JSON.stringify(value)}`;
|
|
640
|
+
};
|
|
641
|
+
whenFn.fieldIn = (field, ...values) => {
|
|
642
|
+
const flat = values.flat();
|
|
643
|
+
return `${field} in [${flat.map((v) => JSON.stringify(v)).join(", ")}]`;
|
|
644
|
+
};
|
|
645
|
+
whenFn.fieldNotIn = (field, ...values) => {
|
|
646
|
+
const flat = values.flat();
|
|
647
|
+
return `!(${field} in [${flat.map((v) => JSON.stringify(v)).join(", ")}])`;
|
|
648
|
+
};
|
|
649
|
+
whenFn.fieldNotEmpty = (field) => {
|
|
650
|
+
return `${field} != null && ${field} != ''`;
|
|
651
|
+
};
|
|
652
|
+
whenFn.fieldEmpty = (field) => {
|
|
653
|
+
return `${field} == null || ${field} == ''`;
|
|
654
|
+
};
|
|
655
|
+
whenFn.fieldIsTrue = (field) => {
|
|
656
|
+
return `${field} == true`;
|
|
657
|
+
};
|
|
658
|
+
whenFn.fieldIsFalse = (field) => {
|
|
659
|
+
return `${field} != true`;
|
|
660
|
+
};
|
|
661
|
+
whenFn.fieldGreaterThan = (field, value) => {
|
|
662
|
+
return `${field} > ${value}`;
|
|
663
|
+
};
|
|
664
|
+
whenFn.fieldGreaterThanOrEqual = (field, value) => {
|
|
665
|
+
return `${field} >= ${value}`;
|
|
666
|
+
};
|
|
667
|
+
whenFn.fieldLessThan = (field, value) => {
|
|
668
|
+
return `${field} < ${value}`;
|
|
669
|
+
};
|
|
670
|
+
whenFn.fieldLessThanOrEqual = (field, value) => {
|
|
671
|
+
return `${field} <= ${value}`;
|
|
672
|
+
};
|
|
673
|
+
whenFn.fieldBetween = (field, min2, max2) => {
|
|
674
|
+
return `${field} >= ${min2} && ${field} <= ${max2}`;
|
|
675
|
+
};
|
|
676
|
+
whenFn.fieldStartsWith = (field, prefix) => {
|
|
677
|
+
return `startsWith(${field}, ${JSON.stringify(prefix)})`;
|
|
678
|
+
};
|
|
679
|
+
whenFn.fieldEndsWith = (field, suffix) => {
|
|
680
|
+
return `endsWith(${field}, ${JSON.stringify(suffix)})`;
|
|
681
|
+
};
|
|
682
|
+
whenFn.fieldContains = (field, item) => {
|
|
683
|
+
return `includes(${field}, ${JSON.stringify(item)})`;
|
|
684
|
+
};
|
|
685
|
+
whenFn.arrayNotEmpty = (field) => {
|
|
686
|
+
return `length(${field}) > 0`;
|
|
687
|
+
};
|
|
688
|
+
whenFn.arrayEmpty = (field) => {
|
|
689
|
+
return `length(${field}) == 0`;
|
|
690
|
+
};
|
|
691
|
+
whenFn.arrayCountGreaterThan = (field, count2) => {
|
|
692
|
+
return `length(${field}) > ${count2}`;
|
|
693
|
+
};
|
|
694
|
+
whenFn.arrayCountAtLeast = (field, count2) => {
|
|
695
|
+
return `length(${field}) >= ${count2}`;
|
|
696
|
+
};
|
|
697
|
+
whenFn.arrayCountLessThan = (field, count2) => {
|
|
698
|
+
return `length(${field}) < ${count2}`;
|
|
699
|
+
};
|
|
700
|
+
whenFn.userRole = (...roles) => {
|
|
701
|
+
const flat = roles.flat();
|
|
702
|
+
if (flat.length === 1) {
|
|
703
|
+
return `user.role == '${flat[0]}' || (user.roles != null && '${flat[0]}' in user.roles)`;
|
|
704
|
+
}
|
|
705
|
+
const roleArray = `[${flat.map((r) => `'${r}'`).join(", ")}]`;
|
|
706
|
+
return `user.role in ${roleArray} || (user.roles != null && includes(${roleArray}, user.role))`;
|
|
707
|
+
};
|
|
708
|
+
whenFn.userEmailDomain = (domain) => {
|
|
709
|
+
const clean = domain.startsWith("@") ? domain : `@${domain}`;
|
|
710
|
+
return `endsWith(user.email, '${clean}')`;
|
|
711
|
+
};
|
|
712
|
+
whenFn.userAttributeEquals = (attr, value) => {
|
|
713
|
+
return `user.${attr} == ${JSON.stringify(value)}`;
|
|
714
|
+
};
|
|
715
|
+
whenFn.isNewDocument = () => {
|
|
716
|
+
return "id == null";
|
|
717
|
+
};
|
|
718
|
+
whenFn.isExistingDocument = () => {
|
|
719
|
+
return "id != null";
|
|
720
|
+
};
|
|
721
|
+
whenFn.statusEquals = (status) => {
|
|
722
|
+
return `status == '${status}'`;
|
|
723
|
+
};
|
|
724
|
+
whenFn.statusIn = (...statuses) => {
|
|
725
|
+
const flat = statuses.flat();
|
|
726
|
+
return `status in [${flat.map((s) => `'${s}'`).join(", ")}]`;
|
|
727
|
+
};
|
|
728
|
+
return whenFn;
|
|
729
|
+
}
|
|
730
|
+
var when = createWhen();
|
|
731
|
+
|
|
366
732
|
// src/index.ts
|
|
367
733
|
function defineCollection(config) {
|
|
368
734
|
return config;
|
|
@@ -413,8 +779,10 @@ function defineTab(args) {
|
|
|
413
779
|
export {
|
|
414
780
|
BUILTIN_JEXL_HELPERS,
|
|
415
781
|
ConfigValidationError,
|
|
782
|
+
FieldConditionBuilder,
|
|
416
783
|
LIFECYCLE_EVENTS_COLLECTION,
|
|
417
784
|
LIFECYCLE_EVENT_NAMES,
|
|
785
|
+
MatchBuilder,
|
|
418
786
|
WORKFLOW_HISTORY_COLLECTION,
|
|
419
787
|
abs,
|
|
420
788
|
addDays,
|
|
@@ -496,6 +864,7 @@ export {
|
|
|
496
864
|
floor,
|
|
497
865
|
formatConfigDiagnostics,
|
|
498
866
|
formatDate,
|
|
867
|
+
formatJexlValue,
|
|
499
868
|
generateDefaultDetailSchema,
|
|
500
869
|
generateOpenApi,
|
|
501
870
|
get,
|
|
@@ -547,6 +916,7 @@ export {
|
|
|
547
916
|
validateDeclarativeAccessExpression,
|
|
548
917
|
validateDeclarativeHookExpression,
|
|
549
918
|
validatePreviewUrlExpression,
|
|
919
|
+
when,
|
|
550
920
|
wordCount,
|
|
551
921
|
workflowCapabilities
|
|
552
922
|
};
|