@stndrds/schema 1.0.0-alpha.112 → 1.0.0-alpha.113
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/index.d.mts +1010 -837
- package/dist/index.d.ts +1010 -837
- package/dist/index.js +348 -0
- package/dist/index.mjs +331 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ require('./chunk-P2BE2A2G.js');
|
|
|
22
22
|
var chunkT225DB55_js = require('./chunk-T225DB55.js');
|
|
23
23
|
var constants = require('@stndrds/constants');
|
|
24
24
|
var z3 = require('zod');
|
|
25
|
+
var exprEval = require('expr-eval');
|
|
25
26
|
|
|
26
27
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
28
|
|
|
@@ -4842,6 +4843,335 @@ var FormRegistry = class {
|
|
|
4842
4843
|
}
|
|
4843
4844
|
};
|
|
4844
4845
|
var formRegistry = new FormRegistry();
|
|
4846
|
+
var DOS_PROTECTION_LIMITS = {
|
|
4847
|
+
MAX_EXPRESSION_LENGTH: 1e4,
|
|
4848
|
+
MAX_TOKEN_COUNT: 1e3,
|
|
4849
|
+
MAX_NESTING_DEPTH: 50
|
|
4850
|
+
};
|
|
4851
|
+
function createFormulaParser() {
|
|
4852
|
+
const parser = new exprEval.Parser();
|
|
4853
|
+
parser.functions.IF = (condition, thenValue, elseValue) => condition ? thenValue : elseValue;
|
|
4854
|
+
parser.functions.AND = (...args) => args.every(Boolean);
|
|
4855
|
+
parser.functions.OR = (...args) => args.some(Boolean);
|
|
4856
|
+
parser.functions.NOT = (value) => !value;
|
|
4857
|
+
parser.functions.EMPTY = (value) => value === null || value === void 0 || value === "";
|
|
4858
|
+
parser.functions.COALESCE = (...args) => args.find((a) => a != null) ?? null;
|
|
4859
|
+
parser.functions.DEFAULT = (value, defaultValue) => value == null || value === "" ? defaultValue : value;
|
|
4860
|
+
parser.functions.CONCAT = (...args) => args.filter((a) => a != null).map(String).join("");
|
|
4861
|
+
parser.functions.UPPER = (value) => String(value ?? "").toUpperCase();
|
|
4862
|
+
parser.functions.LOWER = (value) => String(value ?? "").toLowerCase();
|
|
4863
|
+
parser.functions.TRIM = (value) => String(value ?? "").trim();
|
|
4864
|
+
parser.functions.LENGTH = (value) => String(value ?? "").length;
|
|
4865
|
+
parser.functions.LEFT = (value, count) => String(value ?? "").slice(0, count);
|
|
4866
|
+
parser.functions.RIGHT = (value, count) => String(value ?? "").slice(-count);
|
|
4867
|
+
parser.functions.REPLACE = (value, search, replacement) => String(value ?? "").split(String(search)).join(replacement);
|
|
4868
|
+
parser.functions.CONTAINS = (value, search) => String(value ?? "").toLowerCase().includes(String(search).toLowerCase());
|
|
4869
|
+
parser.functions.ROUND = (value, decimals = 0) => {
|
|
4870
|
+
if (typeof value !== "number" || Number.isNaN(value)) return null;
|
|
4871
|
+
const factor = 10 ** decimals;
|
|
4872
|
+
return Math.round(value * factor) / factor;
|
|
4873
|
+
};
|
|
4874
|
+
parser.functions.FLOOR = (value) => {
|
|
4875
|
+
if (typeof value !== "number" || Number.isNaN(value)) return null;
|
|
4876
|
+
return Math.floor(value);
|
|
4877
|
+
};
|
|
4878
|
+
parser.functions.CEIL = (value) => {
|
|
4879
|
+
if (typeof value !== "number" || Number.isNaN(value)) return null;
|
|
4880
|
+
return Math.ceil(value);
|
|
4881
|
+
};
|
|
4882
|
+
parser.functions.ABS = (value) => {
|
|
4883
|
+
if (typeof value !== "number" || Number.isNaN(value)) return null;
|
|
4884
|
+
return Math.abs(value);
|
|
4885
|
+
};
|
|
4886
|
+
parser.functions.MIN = (...args) => {
|
|
4887
|
+
const nums = args.filter((n) => typeof n === "number" && !Number.isNaN(n));
|
|
4888
|
+
return nums.length > 0 ? Math.min(...nums) : null;
|
|
4889
|
+
};
|
|
4890
|
+
parser.functions.MAX = (...args) => {
|
|
4891
|
+
const nums = args.filter((n) => typeof n === "number" && !Number.isNaN(n));
|
|
4892
|
+
return nums.length > 0 ? Math.max(...nums) : null;
|
|
4893
|
+
};
|
|
4894
|
+
parser.functions.POW = (base, exponent) => {
|
|
4895
|
+
if (typeof base !== "number" || typeof exponent !== "number") return null;
|
|
4896
|
+
if (exponent > 1e3 || exponent < -1e3) return null;
|
|
4897
|
+
return base ** exponent;
|
|
4898
|
+
};
|
|
4899
|
+
parser.functions.MOD = (a, b) => {
|
|
4900
|
+
if (typeof a !== "number" || typeof b !== "number" || b === 0) return null;
|
|
4901
|
+
return a % b;
|
|
4902
|
+
};
|
|
4903
|
+
parser.functions.NOW = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
4904
|
+
parser.functions.TODAY = () => (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
4905
|
+
parser.functions.YEAR = (value) => {
|
|
4906
|
+
const date2 = parseDate(value);
|
|
4907
|
+
return date2 ? date2.getFullYear() : null;
|
|
4908
|
+
};
|
|
4909
|
+
parser.functions.MONTH = (value) => {
|
|
4910
|
+
const date2 = parseDate(value);
|
|
4911
|
+
return date2 ? date2.getMonth() + 1 : null;
|
|
4912
|
+
};
|
|
4913
|
+
parser.functions.DAY = (value) => {
|
|
4914
|
+
const date2 = parseDate(value);
|
|
4915
|
+
return date2 ? date2.getDate() : null;
|
|
4916
|
+
};
|
|
4917
|
+
parser.functions.DATE_DIFF = (date1, date2, unit = "days") => {
|
|
4918
|
+
const d1 = parseDate(date1);
|
|
4919
|
+
const d2 = parseDate(date2);
|
|
4920
|
+
if (d1 === null || d2 === null) return null;
|
|
4921
|
+
const diffMs = d1.getTime() - d2.getTime();
|
|
4922
|
+
const MS_PER_DAY = 1e3 * 60 * 60 * 24;
|
|
4923
|
+
const conversions = {
|
|
4924
|
+
years: MS_PER_DAY * 365,
|
|
4925
|
+
months: MS_PER_DAY * 30,
|
|
4926
|
+
weeks: MS_PER_DAY * 7,
|
|
4927
|
+
days: MS_PER_DAY,
|
|
4928
|
+
hours: 1e3 * 60 * 60,
|
|
4929
|
+
minutes: 1e3 * 60
|
|
4930
|
+
};
|
|
4931
|
+
const divisor = conversions[unit] ?? MS_PER_DAY;
|
|
4932
|
+
return diffMs / divisor;
|
|
4933
|
+
};
|
|
4934
|
+
return parser;
|
|
4935
|
+
}
|
|
4936
|
+
function parseDate(value) {
|
|
4937
|
+
if (!value) return null;
|
|
4938
|
+
if (value instanceof Date) return value;
|
|
4939
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
4940
|
+
const date2 = new Date(value);
|
|
4941
|
+
return Number.isNaN(date2.getTime()) ? null : date2;
|
|
4942
|
+
}
|
|
4943
|
+
return null;
|
|
4944
|
+
}
|
|
4945
|
+
var formulaParser = createFormulaParser();
|
|
4946
|
+
function validateFormulaComplexity(expression) {
|
|
4947
|
+
if (expression.length > DOS_PROTECTION_LIMITS.MAX_EXPRESSION_LENGTH) {
|
|
4948
|
+
return {
|
|
4949
|
+
valid: false,
|
|
4950
|
+
error: `Expression too long (${expression.length} chars, max ${DOS_PROTECTION_LIMITS.MAX_EXPRESSION_LENGTH})`
|
|
4951
|
+
};
|
|
4952
|
+
}
|
|
4953
|
+
const nestingDepth = calculateNestingDepth(expression);
|
|
4954
|
+
if (nestingDepth > DOS_PROTECTION_LIMITS.MAX_NESTING_DEPTH) {
|
|
4955
|
+
return {
|
|
4956
|
+
valid: false,
|
|
4957
|
+
error: `Expression too deeply nested (${nestingDepth} levels, max ${DOS_PROTECTION_LIMITS.MAX_NESTING_DEPTH})`
|
|
4958
|
+
};
|
|
4959
|
+
}
|
|
4960
|
+
try {
|
|
4961
|
+
formulaParser.parse(expression);
|
|
4962
|
+
const tokenCountApprox = estimateTokenCount(expression);
|
|
4963
|
+
if (tokenCountApprox > DOS_PROTECTION_LIMITS.MAX_TOKEN_COUNT) {
|
|
4964
|
+
return {
|
|
4965
|
+
valid: false,
|
|
4966
|
+
error: `Expression too complex (approx ${tokenCountApprox} tokens, max ${DOS_PROTECTION_LIMITS.MAX_TOKEN_COUNT})`
|
|
4967
|
+
};
|
|
4968
|
+
}
|
|
4969
|
+
return { valid: true };
|
|
4970
|
+
} catch {
|
|
4971
|
+
return { valid: true };
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
function estimateTokenCount(expression) {
|
|
4975
|
+
const tokens = expression.match(/-?\d+\.?\d*|[a-zA-Z_][a-zA-Z0-9_]*|[+\-*/(),.><=!&|]+|'(?:[^'\\]|\\.)*'/g) ?? [];
|
|
4976
|
+
return tokens.length;
|
|
4977
|
+
}
|
|
4978
|
+
function calculateNestingDepth(expression) {
|
|
4979
|
+
let maxDepth = 0;
|
|
4980
|
+
let currentDepth = 0;
|
|
4981
|
+
for (const char of expression) {
|
|
4982
|
+
if (char === "(") {
|
|
4983
|
+
currentDepth++;
|
|
4984
|
+
if (currentDepth > maxDepth) maxDepth = currentDepth;
|
|
4985
|
+
} else if (char === ")") {
|
|
4986
|
+
currentDepth--;
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4989
|
+
return maxDepth;
|
|
4990
|
+
}
|
|
4991
|
+
function evaluateFormula(expression, values) {
|
|
4992
|
+
try {
|
|
4993
|
+
const complexityCheck = validateFormulaComplexity(expression);
|
|
4994
|
+
if (!complexityCheck.valid) return null;
|
|
4995
|
+
const parsed = formulaParser.parse(expression);
|
|
4996
|
+
return parsed.evaluate(values);
|
|
4997
|
+
} catch {
|
|
4998
|
+
return null;
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
function evaluateFormulaWithResult(expression, values) {
|
|
5002
|
+
try {
|
|
5003
|
+
const complexityCheck = validateFormulaComplexity(expression);
|
|
5004
|
+
if (!complexityCheck.valid) {
|
|
5005
|
+
return { value: null, error: complexityCheck.error };
|
|
5006
|
+
}
|
|
5007
|
+
const parsed = formulaParser.parse(expression);
|
|
5008
|
+
const value = parsed.evaluate(values);
|
|
5009
|
+
return { value };
|
|
5010
|
+
} catch (error) {
|
|
5011
|
+
return { value: null, error: getErrorMessage(error) };
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
function formatFormulaResult(value, returnType, decimals) {
|
|
5015
|
+
if (value === null || value === void 0) return null;
|
|
5016
|
+
switch (returnType) {
|
|
5017
|
+
case "number": {
|
|
5018
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
5019
|
+
if (Number.isNaN(num)) return null;
|
|
5020
|
+
return decimals !== void 0 ? Number(num.toFixed(decimals)) : num;
|
|
5021
|
+
}
|
|
5022
|
+
case "boolean":
|
|
5023
|
+
return Boolean(value);
|
|
5024
|
+
case "date":
|
|
5025
|
+
if (value instanceof Date) return value.toISOString();
|
|
5026
|
+
if (typeof value === "string") return value;
|
|
5027
|
+
return null;
|
|
5028
|
+
case "text":
|
|
5029
|
+
return String(value);
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
function evaluateFormulaAttribute(attr, values) {
|
|
5033
|
+
const raw = evaluateFormula(attr.expression, values);
|
|
5034
|
+
return formatFormulaResult(raw, attr.returnType, attr.decimals);
|
|
5035
|
+
}
|
|
5036
|
+
function validateFormulaExpression(expression) {
|
|
5037
|
+
try {
|
|
5038
|
+
const complexityCheck = validateFormulaComplexity(expression);
|
|
5039
|
+
if (!complexityCheck.valid) return complexityCheck;
|
|
5040
|
+
formulaParser.parse(expression);
|
|
5041
|
+
return { valid: true };
|
|
5042
|
+
} catch (error) {
|
|
5043
|
+
return { valid: false, error: getErrorMessage(error) };
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
function extractFormulaVariables(expression) {
|
|
5047
|
+
try {
|
|
5048
|
+
const parsed = formulaParser.parse(expression);
|
|
5049
|
+
return parsed.variables();
|
|
5050
|
+
} catch {
|
|
5051
|
+
return [];
|
|
5052
|
+
}
|
|
5053
|
+
}
|
|
5054
|
+
var RELATION_REF_PATTERN = /\b([a-zA-Z_][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)\b/g;
|
|
5055
|
+
function extractRelationReferences(expression) {
|
|
5056
|
+
const regex = new RegExp(RELATION_REF_PATTERN.source, "g");
|
|
5057
|
+
const matches = expression.matchAll(regex);
|
|
5058
|
+
return [...matches].map((m) => m[0]);
|
|
5059
|
+
}
|
|
5060
|
+
function extractRelationNames(expression) {
|
|
5061
|
+
const refs = extractRelationReferences(expression);
|
|
5062
|
+
const names = refs.map((ref) => ref.split(".")[0]);
|
|
5063
|
+
return [...new Set(names)];
|
|
5064
|
+
}
|
|
5065
|
+
function hasRelationReferences(expression) {
|
|
5066
|
+
const regex = new RegExp(RELATION_REF_PATTERN.source);
|
|
5067
|
+
return regex.test(expression);
|
|
5068
|
+
}
|
|
5069
|
+
function flattenRelationsForEval(resolvedRelations) {
|
|
5070
|
+
const result = {};
|
|
5071
|
+
for (const [relationName, values] of Object.entries(resolvedRelations)) {
|
|
5072
|
+
result[relationName] = { ...values };
|
|
5073
|
+
}
|
|
5074
|
+
return result;
|
|
5075
|
+
}
|
|
5076
|
+
|
|
5077
|
+
// src/formula/path-parser.ts
|
|
5078
|
+
var InvalidPathError = class extends Error {
|
|
5079
|
+
constructor(path, segment, reason) {
|
|
5080
|
+
super(`Invalid path "${path}" at "${segment}": ${reason}`);
|
|
5081
|
+
this.path = path;
|
|
5082
|
+
this.segment = segment;
|
|
5083
|
+
this.reason = reason;
|
|
5084
|
+
this.name = "InvalidPathError";
|
|
5085
|
+
}
|
|
5086
|
+
};
|
|
5087
|
+
var MaxDepthExceededError = class extends Error {
|
|
5088
|
+
constructor(path, maxDepth) {
|
|
5089
|
+
super(`Path "${path}" exceeds maximum depth of ${maxDepth}`);
|
|
5090
|
+
this.path = path;
|
|
5091
|
+
this.maxDepth = maxDepth;
|
|
5092
|
+
this.name = "MaxDepthExceededError";
|
|
5093
|
+
}
|
|
5094
|
+
};
|
|
5095
|
+
async function parsePath(path, startSchema, getSchema, maxDepth = 5) {
|
|
5096
|
+
const segments = path.split(".");
|
|
5097
|
+
if (segments.length === 0 || segments.length === 1 && segments[0] === "") {
|
|
5098
|
+
throw new InvalidPathError(path, path, "Path cannot be empty");
|
|
5099
|
+
}
|
|
5100
|
+
if (segments.length > maxDepth) {
|
|
5101
|
+
throw new MaxDepthExceededError(path, maxDepth);
|
|
5102
|
+
}
|
|
5103
|
+
const result = [];
|
|
5104
|
+
let currentSchema = startSchema;
|
|
5105
|
+
for (let i = 0; i < segments.length; i++) {
|
|
5106
|
+
const segmentName = segments[i];
|
|
5107
|
+
const isLastSegment = i === segments.length - 1;
|
|
5108
|
+
const attr = currentSchema.attributes.find((a) => a.name === segmentName);
|
|
5109
|
+
if (!attr) {
|
|
5110
|
+
throw new InvalidPathError(
|
|
5111
|
+
path,
|
|
5112
|
+
segmentName,
|
|
5113
|
+
`Attribute "${segmentName}" not found in object "${currentSchema.name}"`
|
|
5114
|
+
);
|
|
5115
|
+
}
|
|
5116
|
+
if (attr.type === "relation") {
|
|
5117
|
+
const relationAttr = attr;
|
|
5118
|
+
const targetObject = relationAttr.targets[0]?.object;
|
|
5119
|
+
if (!targetObject) {
|
|
5120
|
+
throw new InvalidPathError(path, segmentName, "Relation has no target object");
|
|
5121
|
+
}
|
|
5122
|
+
result.push({
|
|
5123
|
+
name: segmentName,
|
|
5124
|
+
type: "relation",
|
|
5125
|
+
cardinality: relationAttr.cardinality,
|
|
5126
|
+
targetObject
|
|
5127
|
+
});
|
|
5128
|
+
if (!isLastSegment) {
|
|
5129
|
+
const nextSchema = await getSchema(targetObject);
|
|
5130
|
+
if (!nextSchema) {
|
|
5131
|
+
throw new InvalidPathError(
|
|
5132
|
+
path,
|
|
5133
|
+
segmentName,
|
|
5134
|
+
`Target object "${targetObject}" schema not found`
|
|
5135
|
+
);
|
|
5136
|
+
}
|
|
5137
|
+
currentSchema = nextSchema;
|
|
5138
|
+
}
|
|
5139
|
+
} else {
|
|
5140
|
+
if (!isLastSegment) {
|
|
5141
|
+
throw new InvalidPathError(
|
|
5142
|
+
path,
|
|
5143
|
+
segmentName,
|
|
5144
|
+
`"${segmentName}" is not a relation but has segments after it`
|
|
5145
|
+
);
|
|
5146
|
+
}
|
|
5147
|
+
result.push({ name: segmentName, type: "attribute" });
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
return result;
|
|
5151
|
+
}
|
|
5152
|
+
async function validatePath(path, startSchema, getSchema, maxDepth = 5) {
|
|
5153
|
+
try {
|
|
5154
|
+
await parsePath(path, startSchema, getSchema, maxDepth);
|
|
5155
|
+
return true;
|
|
5156
|
+
} catch {
|
|
5157
|
+
return false;
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
function pathHasManyCardinality(segments) {
|
|
5161
|
+
return segments.some((s) => s.type === "relation" && s.cardinality === "many");
|
|
5162
|
+
}
|
|
5163
|
+
function getPathDepth(segments) {
|
|
5164
|
+
return segments.filter((s) => s.type === "relation").length;
|
|
5165
|
+
}
|
|
5166
|
+
function getTargetAttributeName(path) {
|
|
5167
|
+
const parts = path.split(".");
|
|
5168
|
+
return parts[parts.length - 1];
|
|
5169
|
+
}
|
|
5170
|
+
function getRelationPath(path) {
|
|
5171
|
+
const parts = path.split(".");
|
|
5172
|
+
if (parts.length <= 1) return null;
|
|
5173
|
+
return parts.slice(0, -1).join(".");
|
|
5174
|
+
}
|
|
4845
5175
|
|
|
4846
5176
|
Object.defineProperty(exports, "asTenantId", {
|
|
4847
5177
|
enumerable: true,
|
|
@@ -4923,8 +5253,10 @@ exports.FormRowBuilder = FormRowBuilder;
|
|
|
4923
5253
|
exports.FormStepBuilder = FormStepBuilder;
|
|
4924
5254
|
exports.GroupBuilder = GroupBuilder;
|
|
4925
5255
|
exports.IDENTITY_PROPERTIES = IDENTITY_PROPERTIES;
|
|
5256
|
+
exports.InvalidPathError = InvalidPathError;
|
|
4926
5257
|
exports.ListViewBuilder = ListViewBuilder;
|
|
4927
5258
|
exports.ListViewTabConfigBuilder = ListViewTabConfigBuilder;
|
|
5259
|
+
exports.MaxDepthExceededError = MaxDepthExceededError;
|
|
4928
5260
|
exports.MemoryNotFoundError = MemoryNotFoundError;
|
|
4929
5261
|
exports.NO_VALUE_OPERATORS = NO_VALUE_OPERATORS;
|
|
4930
5262
|
exports.NoopGeocodingAdapter = NoopGeocodingAdapter;
|
|
@@ -4971,21 +5303,33 @@ exports.currency = currency;
|
|
|
4971
5303
|
exports.date = date;
|
|
4972
5304
|
exports.detailView = detailView;
|
|
4973
5305
|
exports.document = document;
|
|
5306
|
+
exports.evaluateFormula = evaluateFormula;
|
|
5307
|
+
exports.evaluateFormulaAttribute = evaluateFormulaAttribute;
|
|
5308
|
+
exports.evaluateFormulaWithResult = evaluateFormulaWithResult;
|
|
4974
5309
|
exports.extractAttributeNames = extractAttributeNames;
|
|
5310
|
+
exports.extractFormulaVariables = extractFormulaVariables;
|
|
5311
|
+
exports.extractRelationNames = extractRelationNames;
|
|
5312
|
+
exports.extractRelationReferences = extractRelationReferences;
|
|
4975
5313
|
exports.file = file;
|
|
4976
5314
|
exports.flagRegistry = flagRegistry;
|
|
5315
|
+
exports.flattenRelationsForEval = flattenRelationsForEval;
|
|
4977
5316
|
exports.form = form;
|
|
4978
5317
|
exports.formRegistry = formRegistry;
|
|
4979
5318
|
exports.formatAttributeValue = formatAttributeValue;
|
|
5319
|
+
exports.formatFormulaResult = formatFormulaResult;
|
|
4980
5320
|
exports.formula = formula;
|
|
4981
5321
|
exports.generateDefaultDetailView = generateDefaultDetailView;
|
|
4982
5322
|
exports.generateDefaultListView = generateDefaultListView;
|
|
4983
5323
|
exports.getActiveTab = getActiveTab;
|
|
4984
5324
|
exports.getErrorMessage = getErrorMessage;
|
|
5325
|
+
exports.getPathDepth = getPathDepth;
|
|
5326
|
+
exports.getRelationPath = getRelationPath;
|
|
4985
5327
|
exports.getRollupFilterOperators = getRollupFilterOperators;
|
|
4986
5328
|
exports.getSystemAttributeList = getSystemAttributeList;
|
|
5329
|
+
exports.getTargetAttributeName = getTargetAttributeName;
|
|
4987
5330
|
exports.group = group;
|
|
4988
5331
|
exports.hasOptions = hasOptions;
|
|
5332
|
+
exports.hasRelationReferences = hasRelationReferences;
|
|
4989
5333
|
exports.inferInverseCardinality = inferInverseCardinality;
|
|
4990
5334
|
exports.isAttributeInUseError = isAttributeInUseError;
|
|
4991
5335
|
exports.isAttributeSortable = isAttributeSortable;
|
|
@@ -5021,6 +5365,8 @@ exports.multiselect = multiselect;
|
|
|
5021
5365
|
exports.number = number;
|
|
5022
5366
|
exports.numberFlag = numberFlag;
|
|
5023
5367
|
exports.object = object;
|
|
5368
|
+
exports.parsePath = parsePath;
|
|
5369
|
+
exports.pathHasManyCardinality = pathHasManyCardinality;
|
|
5024
5370
|
exports.phone = phone;
|
|
5025
5371
|
exports.rating = rating;
|
|
5026
5372
|
exports.registry = registry;
|
|
@@ -5038,4 +5384,6 @@ exports.textarea = textarea;
|
|
|
5038
5384
|
exports.toUndefinedIfEmpty = toUndefinedIfEmpty;
|
|
5039
5385
|
exports.user = user;
|
|
5040
5386
|
exports.validateAttributeName = validateAttributeName;
|
|
5387
|
+
exports.validateFormulaExpression = validateFormulaExpression;
|
|
5388
|
+
exports.validatePath = validatePath;
|
|
5041
5389
|
exports.viewRegistry = viewRegistry;
|