@cratis/scene.engine 4.17.0 → 4.18.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/cjs/editing/iconDiagnostics.js +7 -0
- package/dist/cjs/editing/iconDiagnostics.js.map +1 -1
- package/dist/cjs/editing/validateValue.js +12 -2
- package/dist/cjs/editing/validateValue.js.map +1 -1
- package/dist/esm/editing/iconDiagnostics.d.ts.map +1 -1
- package/dist/esm/editing/iconDiagnostics.js +7 -0
- package/dist/esm/editing/iconDiagnostics.js.map +1 -1
- package/dist/esm/editing/validateValue.d.ts.map +1 -1
- package/dist/esm/editing/validateValue.js +12 -2
- package/dist/esm/editing/validateValue.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/editing/iconDiagnostics.ts +6 -0
- package/editing/validateValue.ts +16 -2
- package/package.json +3 -3
|
@@ -94,6 +94,13 @@ const codes = {
|
|
|
94
94
|
path: descriptor.path
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
|
+
if (descriptor.valueType === scene_model.PropertyValueType.Object && descriptor.properties !== undefined && value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
98
|
+
const record = value;
|
|
99
|
+
return descriptor.properties.flatMap((field)=>iconProblemsOfProperty(catalog, {
|
|
100
|
+
...field,
|
|
101
|
+
path: `${descriptor.path}.${field.path}`
|
|
102
|
+
}, record[field.path], severity, context));
|
|
103
|
+
}
|
|
97
104
|
return [];
|
|
98
105
|
}
|
|
99
106
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iconDiagnostics.js","sources":["../../../editing/iconDiagnostics.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CollectionItemDescriptor, DiagnosticCode, DiagnosticSeverity, PropertyDescriptor, PropertyValueType, SceneDiagnostic, isIconReference } from '@cratis/scene.model';\nimport { EffectiveIconCatalog } from '../icons/EffectiveIconCatalog';\nimport { IconDiagnosticKind } from '../icons/IconDiagnostic';\nimport { DiagnosticContext } from './diagnostics';\n\nconst codes: Record<IconDiagnosticKind, DiagnosticCode> = {\n 'missing-library': DiagnosticCode.MissingIconLibrary,\n 'missing-icon': DiagnosticCode.MissingIcon,\n 'missing-variant': DiagnosticCode.MissingIconVariant,\n 'incompatible-version': DiagnosticCode.IncompatibleIconLibrary,\n 'catalog-unavailable': DiagnosticCode.IconCatalogUnavailable,\n};\n\n/**\n * Checks one icon value against the effective icon catalog.\n *\n * Nothing is rewritten or dropped: this only reports. A value whose library, icon or variant is missing, or\n * whose library is at an incompatible version, produces a diagnostic of the given severity - an error when\n * the value is being *set* (the edit is refused), a warning when it is already stored (it is kept, and\n * applies again if the icon comes back). A value that cannot be judged yet, because its library's catalog has\n * not been loaded, produces an `IconNotVerified` warning rather than silently passing.\n *\n * @param catalog The effective catalog of the profile being edited.\n * @param value The value; anything that is not an icon reference is left to `validateValue`.\n * @param severity How serious a definite problem is.\n * @param context What the diagnostic is about.\n */\nexport function iconProblem(catalog: EffectiveIconCatalog, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic | undefined {\n if (!isIconReference(value)) return undefined;\n\n const resolution = catalog.lookup(value);\n if (resolution === undefined) {\n return {\n code: DiagnosticCode.IconNotVerified,\n severity: DiagnosticSeverity.Warning,\n message: `The catalog of the icon library '${value.library}' is not loaded, so '${value.key}' could not be verified.`,\n ...context,\n };\n }\n\n return resolution.isResolved ? undefined : { code: codes[resolution.diagnostic.kind], severity, message: `${resolution.diagnostic.message}.`, ...context };\n}\n\n/**\n * Checks the icon fields of collection items.\n *\n * @param itemDescriptor What the items look like.\n * @param items The items, each with its id and field values.\n */\nexport function iconProblemsOfItems(\n catalog: EffectiveIconCatalog,\n itemDescriptor: CollectionItemDescriptor | undefined,\n items: { id: string; values: Record<string, unknown>; instance?: string }[],\n severity: DiagnosticSeverity,\n context: DiagnosticContext\n): SceneDiagnostic[] {\n const iconFields = (itemDescriptor?.properties ?? []).filter((field) => field.valueType === PropertyValueType.Icon);\n return items.flatMap((item) =>\n iconFields.flatMap((field) => {\n const problem = iconProblem(catalog, item.values[field.path], severity, { ...context, itemId: item.id, ...(item.instance === undefined ? {} : { instance: item.instance }) });\n return problem ? [{ ...problem, message: `'${field.label}' of '${item.id}': ${problem.message}` }] : [];\n })\n );\n}\n\n/**\n * Checks a property's value - an icon, or a collection whose items have icon fields - against the effective icon\n * catalog. Any other kind of property has nothing to check.\n *\n * @param descriptor The property.\n * @param value The value; for a collection, the flat items (`{ id, ...fields }`) as they are stored.\n */\nexport function iconProblemsOfProperty(catalog: EffectiveIconCatalog, descriptor: PropertyDescriptor, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic[] {\n if (descriptor.valueType === PropertyValueType.Icon) {\n const problem = iconProblem(catalog, value, severity, { ...context, path: descriptor.path });\n return problem ? [{ ...problem, message: `'${descriptor.label}': ${problem.message}` }] : [];\n }\n\n if (descriptor.valueType === PropertyValueType.Collection && Array.isArray(value)) {\n const items = value\n .filter((item): item is Record<string, unknown> => item !== null && typeof item === 'object')\n .map(({ id, ...values }) => ({ id: String(id), values }));\n return iconProblemsOfItems(catalog, descriptor.item, items, severity, { ...context, path: descriptor.path });\n }\n\n return [];\n}\n"],"names":["codes","DiagnosticCode","MissingIconLibrary","MissingIcon","MissingIconVariant","IncompatibleIconLibrary","IconCatalogUnavailable","iconProblem","catalog","value","severity","context","isIconReference","undefined","resolution","lookup","code","IconNotVerified","DiagnosticSeverity","Warning","message","library","key","isResolved","diagnostic","kind","iconProblemsOfItems","itemDescriptor","items","iconFields","properties","filter","field","valueType","PropertyValueType","Icon","flatMap","item","problem","values","path","itemId","id","instance","label","iconProblemsOfProperty","descriptor","Collection","Array","isArray","map","String"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"iconDiagnostics.js","sources":["../../../editing/iconDiagnostics.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CollectionItemDescriptor, DiagnosticCode, DiagnosticSeverity, PropertyDescriptor, PropertyValueType, SceneDiagnostic, isIconReference } from '@cratis/scene.model';\nimport { EffectiveIconCatalog } from '../icons/EffectiveIconCatalog';\nimport { IconDiagnosticKind } from '../icons/IconDiagnostic';\nimport { DiagnosticContext } from './diagnostics';\n\nconst codes: Record<IconDiagnosticKind, DiagnosticCode> = {\n 'missing-library': DiagnosticCode.MissingIconLibrary,\n 'missing-icon': DiagnosticCode.MissingIcon,\n 'missing-variant': DiagnosticCode.MissingIconVariant,\n 'incompatible-version': DiagnosticCode.IncompatibleIconLibrary,\n 'catalog-unavailable': DiagnosticCode.IconCatalogUnavailable,\n};\n\n/**\n * Checks one icon value against the effective icon catalog.\n *\n * Nothing is rewritten or dropped: this only reports. A value whose library, icon or variant is missing, or\n * whose library is at an incompatible version, produces a diagnostic of the given severity - an error when\n * the value is being *set* (the edit is refused), a warning when it is already stored (it is kept, and\n * applies again if the icon comes back). A value that cannot be judged yet, because its library's catalog has\n * not been loaded, produces an `IconNotVerified` warning rather than silently passing.\n *\n * @param catalog The effective catalog of the profile being edited.\n * @param value The value; anything that is not an icon reference is left to `validateValue`.\n * @param severity How serious a definite problem is.\n * @param context What the diagnostic is about.\n */\nexport function iconProblem(catalog: EffectiveIconCatalog, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic | undefined {\n if (!isIconReference(value)) return undefined;\n\n const resolution = catalog.lookup(value);\n if (resolution === undefined) {\n return {\n code: DiagnosticCode.IconNotVerified,\n severity: DiagnosticSeverity.Warning,\n message: `The catalog of the icon library '${value.library}' is not loaded, so '${value.key}' could not be verified.`,\n ...context,\n };\n }\n\n return resolution.isResolved ? undefined : { code: codes[resolution.diagnostic.kind], severity, message: `${resolution.diagnostic.message}.`, ...context };\n}\n\n/**\n * Checks the icon fields of collection items.\n *\n * @param itemDescriptor What the items look like.\n * @param items The items, each with its id and field values.\n */\nexport function iconProblemsOfItems(\n catalog: EffectiveIconCatalog,\n itemDescriptor: CollectionItemDescriptor | undefined,\n items: { id: string; values: Record<string, unknown>; instance?: string }[],\n severity: DiagnosticSeverity,\n context: DiagnosticContext\n): SceneDiagnostic[] {\n const iconFields = (itemDescriptor?.properties ?? []).filter((field) => field.valueType === PropertyValueType.Icon);\n return items.flatMap((item) =>\n iconFields.flatMap((field) => {\n const problem = iconProblem(catalog, item.values[field.path], severity, { ...context, itemId: item.id, ...(item.instance === undefined ? {} : { instance: item.instance }) });\n return problem ? [{ ...problem, message: `'${field.label}' of '${item.id}': ${problem.message}` }] : [];\n })\n );\n}\n\n/**\n * Checks a property's value - an icon, or a collection whose items have icon fields - against the effective icon\n * catalog. Any other kind of property has nothing to check.\n *\n * @param descriptor The property.\n * @param value The value; for a collection, the flat items (`{ id, ...fields }`) as they are stored.\n */\nexport function iconProblemsOfProperty(catalog: EffectiveIconCatalog, descriptor: PropertyDescriptor, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic[] {\n if (descriptor.valueType === PropertyValueType.Icon) {\n const problem = iconProblem(catalog, value, severity, { ...context, path: descriptor.path });\n return problem ? [{ ...problem, message: `'${descriptor.label}': ${problem.message}` }] : [];\n }\n\n if (descriptor.valueType === PropertyValueType.Collection && Array.isArray(value)) {\n const items = value\n .filter((item): item is Record<string, unknown> => item !== null && typeof item === 'object')\n .map(({ id, ...values }) => ({ id: String(id), values }));\n return iconProblemsOfItems(catalog, descriptor.item, items, severity, { ...context, path: descriptor.path });\n }\n\n if (descriptor.valueType === PropertyValueType.Object && descriptor.properties !== undefined && value !== null && typeof value === 'object' && !Array.isArray(value)) {\n const record = value as Record<string, unknown>;\n return descriptor.properties.flatMap((field) =>\n iconProblemsOfProperty(catalog, { ...field, path: `${descriptor.path}.${field.path}` }, record[field.path], severity, context));\n }\n\n return [];\n}\n"],"names":["codes","DiagnosticCode","MissingIconLibrary","MissingIcon","MissingIconVariant","IncompatibleIconLibrary","IconCatalogUnavailable","iconProblem","catalog","value","severity","context","isIconReference","undefined","resolution","lookup","code","IconNotVerified","DiagnosticSeverity","Warning","message","library","key","isResolved","diagnostic","kind","iconProblemsOfItems","itemDescriptor","items","iconFields","properties","filter","field","valueType","PropertyValueType","Icon","flatMap","item","problem","values","path","itemId","id","instance","label","iconProblemsOfProperty","descriptor","Collection","Array","isArray","map","String","Object","record"],"mappings":"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"}
|
|
@@ -58,6 +58,8 @@ function isNonEmptyString(value) {
|
|
|
58
58
|
return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';
|
|
59
59
|
case scene_model.PropertyValueType.Collection:
|
|
60
60
|
return validateCollection(descriptor, value);
|
|
61
|
+
case scene_model.PropertyValueType.Object:
|
|
62
|
+
return validateObject(descriptor, value);
|
|
61
63
|
case scene_model.PropertyValueType.Json:
|
|
62
64
|
return isJsonValue(value) ? undefined : 'expected a JSON value';
|
|
63
65
|
default:
|
|
@@ -98,6 +100,12 @@ const maximumJsonDepth = 64;
|
|
|
98
100
|
parents.delete(value);
|
|
99
101
|
return valid;
|
|
100
102
|
}
|
|
103
|
+
function validateObject(descriptor, value) {
|
|
104
|
+
if (descriptor.properties === undefined) return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';
|
|
105
|
+
if (!isRecord(value)) return 'expected a structured value';
|
|
106
|
+
const problem = validateFields(descriptor.properties, value, 'this object').at(0);
|
|
107
|
+
return problem ? `${problem.field} ${problem.problem}` : undefined;
|
|
108
|
+
}
|
|
101
109
|
function validateCollection(descriptor, value) {
|
|
102
110
|
if (!Array.isArray(value)) return 'expected a list';
|
|
103
111
|
const constraints = descriptor.constraints ?? {};
|
|
@@ -121,14 +129,16 @@ function validateCollection(descriptor, value) {
|
|
|
121
129
|
* @param values The item's field values, keyed by field path.
|
|
122
130
|
* @returns Every field that is unknown or has an unacceptable value.
|
|
123
131
|
*/ function validateItemValues(itemDescriptor, values) {
|
|
124
|
-
|
|
132
|
+
return validateFields(itemDescriptor?.properties ?? [], values, 'this collection\'s items');
|
|
133
|
+
}
|
|
134
|
+
function validateFields(fields, values, owner) {
|
|
125
135
|
const problems = [];
|
|
126
136
|
for (const [field, fieldValue] of Object.entries(values)){
|
|
127
137
|
const fieldDescriptor = fields.find((candidate)=>candidate.path === field);
|
|
128
138
|
if (!fieldDescriptor) {
|
|
129
139
|
problems.push({
|
|
130
140
|
field,
|
|
131
|
-
problem:
|
|
141
|
+
problem: `is not a field of ${owner}`
|
|
132
142
|
});
|
|
133
143
|
continue;
|
|
134
144
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateValue.js","sources":["../../../editing/validateValue.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingSourceKind, CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * Checks a value against a property descriptor.\n *\n * @param descriptor The property the value is for.\n * @param value The value to check. `undefined` means \"not set\", which is fine unless the property is required.\n * @returns The reason the value is not acceptable, or `undefined` when it is.\n */\nexport function validateValue(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n const constraints = descriptor.constraints ?? {};\n if (value === undefined || value === null) {\n return constraints.required ? 'a value is required' : undefined;\n }\n\n const binding = bindingKindOf(value);\n if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {\n return descriptor.acceptedBindingKinds.includes(binding.kind)\n ? undefined\n : `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;\n }\n\n switch (descriptor.valueType) {\n case PropertyValueType.String: {\n if (typeof value !== 'string') return 'expected a string';\n if (constraints.minimumLength !== undefined && value.length < constraints.minimumLength) return `must be at least ${constraints.minimumLength} characters`;\n if (constraints.maximumLength !== undefined && value.length > constraints.maximumLength) return `must be at most ${constraints.maximumLength} characters`;\n if (constraints.pattern !== undefined && !new RegExp(`^(?:${constraints.pattern})$`).test(value)) return `must match ${constraints.pattern}`;\n return undefined;\n }\n\n case PropertyValueType.Number: {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 'expected a number';\n if (constraints.integer && !Number.isInteger(value)) return 'expected a whole number';\n if (constraints.minimum !== undefined && value < constraints.minimum) return `must be at least ${constraints.minimum}`;\n if (constraints.maximum !== undefined && value > constraints.maximum) return `must be at most ${constraints.maximum}`;\n return undefined;\n }\n\n case PropertyValueType.Boolean:\n return typeof value === 'boolean' ? undefined : 'expected true or false';\n\n case PropertyValueType.Enum:\n return (descriptor.choices ?? []).some(choice => choice.value === value) ? undefined : 'not one of the allowed choices';\n\n case PropertyValueType.Icon:\n if (!isRecord(value) || !isNonEmptyString(value.library) || !isNonEmptyString(value.key)) return 'expected an icon reference with a library and a key';\n return value.variant === undefined || typeof value.variant === 'string' ? undefined : 'the icon variant must be a string';\n\n case PropertyValueType.Destination:\n if (!isRecord(value) || !isNonEmptyString(value.screen)) return 'expected a destination naming a screen';\n return value.routeParameterBindings === undefined || isRecord(value.routeParameterBindings)\n ? undefined\n : 'routeParameterBindings must be an object';\n\n case PropertyValueType.QueryReference:\n if (isNonEmptyString(value)) return undefined;\n if (!isRecord(value) || !isNonEmptyString(value.queryId) || !isNonEmptyString(value.query)) return 'expected a query name or a query binding';\n return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';\n\n case PropertyValueType.Collection:\n return validateCollection(descriptor, value);\n\n case PropertyValueType.Json:\n return isJsonValue(value) ? undefined : 'expected a JSON value';\n\n default:\n return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';\n }\n}\n\n/**\n * The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;\n * the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.\n */\nconst bindingKinds = new Set<string>(Object.values(BindingSourceKind));\n\n/**\n * The source kind of a value that is a typed binding expression - an object with a known `kind` and a\n * string `path` - rather than a value of the property's own type. Only consulted for properties that declare\n * `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a\n * table's `selectedItem` instead of listing its items.\n */\nfunction bindingKindOf(value: unknown): { kind: BindingSourceKind } | undefined {\n if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;\n return { kind: value.kind as BindingSourceKind };\n}\n\nconst maximumJsonDepth = 64;\n\n/**\n * Whether a value is JSON: `null`, a string, a boolean, a finite number, or an array or plain object of those.\n * The value is only inspected, never serialized, so what an editor stores is exactly what was passed in.\n */\nfunction isJsonValue(value: unknown, parents = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || parents.has(value) || parents.size >= maximumJsonDepth) return false;\n\n const isArray = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (isArray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) return false;\n\n parents.add(value);\n const values = isArray ? Array.from({ length: value.length }, (_, index) => (index in value ? value[index] : undefined)) : Object.values(value);\n const valid = values.every(candidate => isJsonValue(candidate, parents));\n parents.delete(value);\n return valid;\n}\n\nfunction validateCollection(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n if (!Array.isArray(value)) return 'expected a list';\n const constraints = descriptor.constraints ?? {};\n if (constraints.minimumItems !== undefined && value.length < constraints.minimumItems) return `needs at least ${constraints.minimumItems} items`;\n if (constraints.maximumItems !== undefined && value.length > constraints.maximumItems) return `allows at most ${constraints.maximumItems} items`;\n\n const identities = new Set<string>();\n for (const item of value) {\n if (!isRecord(item) || !isNonEmptyString(item.id)) return 'every item needs an id';\n if (identities.has(item.id)) return `the item id '${item.id}' is used twice`;\n identities.add(item.id);\n\n const { id: _identity, ...values } = item;\n const problem = validateItemValues(descriptor.item, values).at(0);\n if (problem) return `item '${item.id}': ${problem.field} ${problem.problem}`;\n }\n\n return undefined;\n}\n\n/**\n * One field of a collection item that does not fit its descriptor.\n */\nexport interface ItemFieldProblem {\n field: string;\n problem: string;\n}\n\n/**\n * Checks a collection item's field values against the collection's item descriptor.\n *\n * @param itemDescriptor What the items look like.\n * @param values The item's field values, keyed by field path.\n * @returns Every field that is unknown or has an unacceptable value.\n */\nexport function validateItemValues(itemDescriptor: CollectionItemDescriptor | undefined, values: Record<string, unknown>): ItemFieldProblem[] {\n const fields = itemDescriptor?.properties ?? [];\n const problems: ItemFieldProblem[] = [];\n\n for (const [field, fieldValue] of Object.entries(values)) {\n const fieldDescriptor = fields.find(candidate => candidate.path === field);\n if (!fieldDescriptor) {\n problems.push({ field, problem: 'is not a field of this collection\\'s items' });\n continue;\n }\n\n const problem = validateValue(fieldDescriptor, fieldValue);\n if (problem) problems.push({ field, problem });\n }\n\n for (const fieldDescriptor of fields) {\n if (fieldDescriptor.constraints?.required && values[fieldDescriptor.path] === undefined) {\n problems.push({ field: fieldDescriptor.path, problem: 'a value is required' });\n }\n }\n\n return problems;\n}\n"],"names":["isRecord","value","Array","isArray","isNonEmptyString","length","validateValue","descriptor","constraints","undefined","required","binding","bindingKindOf","acceptedBindingKinds","includes","kind","join","valueType","PropertyValueType","String","minimumLength","maximumLength","pattern","RegExp","test","Number","isFinite","integer","isInteger","minimum","maximum","Boolean","Enum","choices","some","choice","Icon","library","key","variant","Destination","screen","routeParameterBindings","QueryReference","queryId","query","arguments","results","Collection","validateCollection","Json","isJsonValue","bindingKinds","Set","Object","values","BindingSourceKind","has","path","maximumJsonDepth","parents","size","prototype","getPrototypeOf","add","from","_","index","valid","every","candidate","delete","minimumItems","maximumItems","identities","item","id","_identity","problem","validateItemValues","at","field","itemDescriptor","fields","properties","problems","fieldValue","entries","fieldDescriptor","find","push"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validateValue.js","sources":["../../../editing/validateValue.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingSourceKind, CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * Checks a value against a property descriptor.\n *\n * @param descriptor The property the value is for.\n * @param value The value to check. `undefined` means \"not set\", which is fine unless the property is required.\n * @returns The reason the value is not acceptable, or `undefined` when it is.\n */\nexport function validateValue(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n const constraints = descriptor.constraints ?? {};\n if (value === undefined || value === null) {\n return constraints.required ? 'a value is required' : undefined;\n }\n\n const binding = bindingKindOf(value);\n if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {\n return descriptor.acceptedBindingKinds.includes(binding.kind)\n ? undefined\n : `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;\n }\n\n switch (descriptor.valueType) {\n case PropertyValueType.String: {\n if (typeof value !== 'string') return 'expected a string';\n if (constraints.minimumLength !== undefined && value.length < constraints.minimumLength) return `must be at least ${constraints.minimumLength} characters`;\n if (constraints.maximumLength !== undefined && value.length > constraints.maximumLength) return `must be at most ${constraints.maximumLength} characters`;\n if (constraints.pattern !== undefined && !new RegExp(`^(?:${constraints.pattern})$`).test(value)) return `must match ${constraints.pattern}`;\n return undefined;\n }\n\n case PropertyValueType.Number: {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 'expected a number';\n if (constraints.integer && !Number.isInteger(value)) return 'expected a whole number';\n if (constraints.minimum !== undefined && value < constraints.minimum) return `must be at least ${constraints.minimum}`;\n if (constraints.maximum !== undefined && value > constraints.maximum) return `must be at most ${constraints.maximum}`;\n return undefined;\n }\n\n case PropertyValueType.Boolean:\n return typeof value === 'boolean' ? undefined : 'expected true or false';\n\n case PropertyValueType.Enum:\n return (descriptor.choices ?? []).some(choice => choice.value === value) ? undefined : 'not one of the allowed choices';\n\n case PropertyValueType.Icon:\n if (!isRecord(value) || !isNonEmptyString(value.library) || !isNonEmptyString(value.key)) return 'expected an icon reference with a library and a key';\n return value.variant === undefined || typeof value.variant === 'string' ? undefined : 'the icon variant must be a string';\n\n case PropertyValueType.Destination:\n if (!isRecord(value) || !isNonEmptyString(value.screen)) return 'expected a destination naming a screen';\n return value.routeParameterBindings === undefined || isRecord(value.routeParameterBindings)\n ? undefined\n : 'routeParameterBindings must be an object';\n\n case PropertyValueType.QueryReference:\n if (isNonEmptyString(value)) return undefined;\n if (!isRecord(value) || !isNonEmptyString(value.queryId) || !isNonEmptyString(value.query)) return 'expected a query name or a query binding';\n return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';\n\n case PropertyValueType.Collection:\n return validateCollection(descriptor, value);\n\n case PropertyValueType.Object:\n return validateObject(descriptor, value);\n\n case PropertyValueType.Json:\n return isJsonValue(value) ? undefined : 'expected a JSON value';\n\n default:\n return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';\n }\n}\n\n/**\n * The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;\n * the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.\n */\nconst bindingKinds = new Set<string>(Object.values(BindingSourceKind));\n\n/**\n * The source kind of a value that is a typed binding expression - an object with a known `kind` and a\n * string `path` - rather than a value of the property's own type. Only consulted for properties that declare\n * `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a\n * table's `selectedItem` instead of listing its items.\n */\nfunction bindingKindOf(value: unknown): { kind: BindingSourceKind } | undefined {\n if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;\n return { kind: value.kind as BindingSourceKind };\n}\n\nconst maximumJsonDepth = 64;\n\n/**\n * Whether a value is JSON: `null`, a string, a boolean, a finite number, or an array or plain object of those.\n * The value is only inspected, never serialized, so what an editor stores is exactly what was passed in.\n */\nfunction isJsonValue(value: unknown, parents = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || parents.has(value) || parents.size >= maximumJsonDepth) return false;\n\n const isArray = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (isArray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) return false;\n\n parents.add(value);\n const values = isArray ? Array.from({ length: value.length }, (_, index) => (index in value ? value[index] : undefined)) : Object.values(value);\n const valid = values.every(candidate => isJsonValue(candidate, parents));\n parents.delete(value);\n return valid;\n}\n\nfunction validateObject(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n if (descriptor.properties === undefined) return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';\n if (!isRecord(value)) return 'expected a structured value';\n\n const problem = validateFields(descriptor.properties, value, 'this object').at(0);\n return problem ? `${problem.field} ${problem.problem}` : undefined;\n}\n\nfunction validateCollection(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n if (!Array.isArray(value)) return 'expected a list';\n const constraints = descriptor.constraints ?? {};\n if (constraints.minimumItems !== undefined && value.length < constraints.minimumItems) return `needs at least ${constraints.minimumItems} items`;\n if (constraints.maximumItems !== undefined && value.length > constraints.maximumItems) return `allows at most ${constraints.maximumItems} items`;\n\n const identities = new Set<string>();\n for (const item of value) {\n if (!isRecord(item) || !isNonEmptyString(item.id)) return 'every item needs an id';\n if (identities.has(item.id)) return `the item id '${item.id}' is used twice`;\n identities.add(item.id);\n\n const { id: _identity, ...values } = item;\n const problem = validateItemValues(descriptor.item, values).at(0);\n if (problem) return `item '${item.id}': ${problem.field} ${problem.problem}`;\n }\n\n return undefined;\n}\n\n/**\n * One field of a collection item that does not fit its descriptor.\n */\nexport interface ItemFieldProblem {\n field: string;\n problem: string;\n}\n\n/**\n * Checks a collection item's field values against the collection's item descriptor.\n *\n * @param itemDescriptor What the items look like.\n * @param values The item's field values, keyed by field path.\n * @returns Every field that is unknown or has an unacceptable value.\n */\nexport function validateItemValues(itemDescriptor: CollectionItemDescriptor | undefined, values: Record<string, unknown>): ItemFieldProblem[] {\n return validateFields(itemDescriptor?.properties ?? [], values, 'this collection\\'s items');\n}\n\nfunction validateFields(fields: PropertyDescriptor[], values: Record<string, unknown>, owner: string): ItemFieldProblem[] {\n const problems: ItemFieldProblem[] = [];\n\n for (const [field, fieldValue] of Object.entries(values)) {\n const fieldDescriptor = fields.find(candidate => candidate.path === field);\n if (!fieldDescriptor) {\n problems.push({ field, problem: `is not a field of ${owner}` });\n continue;\n }\n\n const problem = validateValue(fieldDescriptor, fieldValue);\n if (problem) problems.push({ field, problem });\n }\n\n for (const fieldDescriptor of fields) {\n if (fieldDescriptor.constraints?.required && values[fieldDescriptor.path] === undefined) {\n problems.push({ field: fieldDescriptor.path, problem: 'a value is required' });\n }\n }\n\n return problems;\n}\n"],"names":["isRecord","value","Array","isArray","isNonEmptyString","length","validateValue","descriptor","constraints","undefined","required","binding","bindingKindOf","acceptedBindingKinds","includes","kind","join","valueType","PropertyValueType","String","minimumLength","maximumLength","pattern","RegExp","test","Number","isFinite","integer","isInteger","minimum","maximum","Boolean","Enum","choices","some","choice","Icon","library","key","variant","Destination","screen","routeParameterBindings","QueryReference","queryId","query","arguments","results","Collection","validateCollection","Object","validateObject","Json","isJsonValue","bindingKinds","Set","values","BindingSourceKind","has","path","maximumJsonDepth","parents","size","prototype","getPrototypeOf","add","from","_","index","valid","every","candidate","delete","properties","problem","validateFields","at","field","minimumItems","maximumItems","identities","item","id","_identity","validateItemValues","itemDescriptor","fields","owner","problems","fieldValue","entries","fieldDescriptor","find","push"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iconDiagnostics.d.ts","sourceRoot":"","sources":["../../../editing/iconDiagnostics.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,wBAAwB,EAAkB,kBAAkB,EAAE,kBAAkB,EAAqB,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAC5K,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAwBlD,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,GAAG,eAAe,GAAG,SAAS,CAchK;AAQD,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,oBAAoB,EAC7B,cAAc,EAAE,wBAAwB,GAAG,SAAS,EACpD,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3E,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,iBAAiB,GAC3B,eAAe,EAAE,CAQnB;AASD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,GAAG,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"iconDiagnostics.d.ts","sourceRoot":"","sources":["../../../editing/iconDiagnostics.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,wBAAwB,EAAkB,kBAAkB,EAAE,kBAAkB,EAAqB,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAC5K,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAwBlD,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,GAAG,eAAe,GAAG,SAAS,CAchK;AAQD,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,oBAAoB,EAC7B,cAAc,EAAE,wBAAwB,GAAG,SAAS,EACpD,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3E,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,iBAAiB,GAC3B,eAAe,EAAE,CAQnB;AASD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,GAAG,eAAe,EAAE,CAoBjM"}
|
|
@@ -92,6 +92,13 @@ const codes = {
|
|
|
92
92
|
path: descriptor.path
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
+
if (descriptor.valueType === PropertyValueType.Object && descriptor.properties !== undefined && value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
96
|
+
const record = value;
|
|
97
|
+
return descriptor.properties.flatMap((field)=>iconProblemsOfProperty(catalog, {
|
|
98
|
+
...field,
|
|
99
|
+
path: `${descriptor.path}.${field.path}`
|
|
100
|
+
}, record[field.path], severity, context));
|
|
101
|
+
}
|
|
95
102
|
return [];
|
|
96
103
|
}
|
|
97
104
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iconDiagnostics.js","sources":["../../../editing/iconDiagnostics.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CollectionItemDescriptor, DiagnosticCode, DiagnosticSeverity, PropertyDescriptor, PropertyValueType, SceneDiagnostic, isIconReference } from '@cratis/scene.model';\nimport { EffectiveIconCatalog } from '../icons/EffectiveIconCatalog';\nimport { IconDiagnosticKind } from '../icons/IconDiagnostic';\nimport { DiagnosticContext } from './diagnostics';\n\nconst codes: Record<IconDiagnosticKind, DiagnosticCode> = {\n 'missing-library': DiagnosticCode.MissingIconLibrary,\n 'missing-icon': DiagnosticCode.MissingIcon,\n 'missing-variant': DiagnosticCode.MissingIconVariant,\n 'incompatible-version': DiagnosticCode.IncompatibleIconLibrary,\n 'catalog-unavailable': DiagnosticCode.IconCatalogUnavailable,\n};\n\n/**\n * Checks one icon value against the effective icon catalog.\n *\n * Nothing is rewritten or dropped: this only reports. A value whose library, icon or variant is missing, or\n * whose library is at an incompatible version, produces a diagnostic of the given severity - an error when\n * the value is being *set* (the edit is refused), a warning when it is already stored (it is kept, and\n * applies again if the icon comes back). A value that cannot be judged yet, because its library's catalog has\n * not been loaded, produces an `IconNotVerified` warning rather than silently passing.\n *\n * @param catalog The effective catalog of the profile being edited.\n * @param value The value; anything that is not an icon reference is left to `validateValue`.\n * @param severity How serious a definite problem is.\n * @param context What the diagnostic is about.\n */\nexport function iconProblem(catalog: EffectiveIconCatalog, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic | undefined {\n if (!isIconReference(value)) return undefined;\n\n const resolution = catalog.lookup(value);\n if (resolution === undefined) {\n return {\n code: DiagnosticCode.IconNotVerified,\n severity: DiagnosticSeverity.Warning,\n message: `The catalog of the icon library '${value.library}' is not loaded, so '${value.key}' could not be verified.`,\n ...context,\n };\n }\n\n return resolution.isResolved ? undefined : { code: codes[resolution.diagnostic.kind], severity, message: `${resolution.diagnostic.message}.`, ...context };\n}\n\n/**\n * Checks the icon fields of collection items.\n *\n * @param itemDescriptor What the items look like.\n * @param items The items, each with its id and field values.\n */\nexport function iconProblemsOfItems(\n catalog: EffectiveIconCatalog,\n itemDescriptor: CollectionItemDescriptor | undefined,\n items: { id: string; values: Record<string, unknown>; instance?: string }[],\n severity: DiagnosticSeverity,\n context: DiagnosticContext\n): SceneDiagnostic[] {\n const iconFields = (itemDescriptor?.properties ?? []).filter((field) => field.valueType === PropertyValueType.Icon);\n return items.flatMap((item) =>\n iconFields.flatMap((field) => {\n const problem = iconProblem(catalog, item.values[field.path], severity, { ...context, itemId: item.id, ...(item.instance === undefined ? {} : { instance: item.instance }) });\n return problem ? [{ ...problem, message: `'${field.label}' of '${item.id}': ${problem.message}` }] : [];\n })\n );\n}\n\n/**\n * Checks a property's value - an icon, or a collection whose items have icon fields - against the effective icon\n * catalog. Any other kind of property has nothing to check.\n *\n * @param descriptor The property.\n * @param value The value; for a collection, the flat items (`{ id, ...fields }`) as they are stored.\n */\nexport function iconProblemsOfProperty(catalog: EffectiveIconCatalog, descriptor: PropertyDescriptor, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic[] {\n if (descriptor.valueType === PropertyValueType.Icon) {\n const problem = iconProblem(catalog, value, severity, { ...context, path: descriptor.path });\n return problem ? [{ ...problem, message: `'${descriptor.label}': ${problem.message}` }] : [];\n }\n\n if (descriptor.valueType === PropertyValueType.Collection && Array.isArray(value)) {\n const items = value\n .filter((item): item is Record<string, unknown> => item !== null && typeof item === 'object')\n .map(({ id, ...values }) => ({ id: String(id), values }));\n return iconProblemsOfItems(catalog, descriptor.item, items, severity, { ...context, path: descriptor.path });\n }\n\n return [];\n}\n"],"names":["codes","DiagnosticCode","MissingIconLibrary","MissingIcon","MissingIconVariant","IncompatibleIconLibrary","IconCatalogUnavailable","iconProblem","catalog","value","severity","context","isIconReference","undefined","resolution","lookup","code","IconNotVerified","DiagnosticSeverity","Warning","message","library","key","isResolved","diagnostic","kind","iconProblemsOfItems","itemDescriptor","items","iconFields","properties","filter","field","valueType","PropertyValueType","Icon","flatMap","item","problem","values","path","itemId","id","instance","label","iconProblemsOfProperty","descriptor","Collection","Array","isArray","map","String"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"iconDiagnostics.js","sources":["../../../editing/iconDiagnostics.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CollectionItemDescriptor, DiagnosticCode, DiagnosticSeverity, PropertyDescriptor, PropertyValueType, SceneDiagnostic, isIconReference } from '@cratis/scene.model';\nimport { EffectiveIconCatalog } from '../icons/EffectiveIconCatalog';\nimport { IconDiagnosticKind } from '../icons/IconDiagnostic';\nimport { DiagnosticContext } from './diagnostics';\n\nconst codes: Record<IconDiagnosticKind, DiagnosticCode> = {\n 'missing-library': DiagnosticCode.MissingIconLibrary,\n 'missing-icon': DiagnosticCode.MissingIcon,\n 'missing-variant': DiagnosticCode.MissingIconVariant,\n 'incompatible-version': DiagnosticCode.IncompatibleIconLibrary,\n 'catalog-unavailable': DiagnosticCode.IconCatalogUnavailable,\n};\n\n/**\n * Checks one icon value against the effective icon catalog.\n *\n * Nothing is rewritten or dropped: this only reports. A value whose library, icon or variant is missing, or\n * whose library is at an incompatible version, produces a diagnostic of the given severity - an error when\n * the value is being *set* (the edit is refused), a warning when it is already stored (it is kept, and\n * applies again if the icon comes back). A value that cannot be judged yet, because its library's catalog has\n * not been loaded, produces an `IconNotVerified` warning rather than silently passing.\n *\n * @param catalog The effective catalog of the profile being edited.\n * @param value The value; anything that is not an icon reference is left to `validateValue`.\n * @param severity How serious a definite problem is.\n * @param context What the diagnostic is about.\n */\nexport function iconProblem(catalog: EffectiveIconCatalog, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic | undefined {\n if (!isIconReference(value)) return undefined;\n\n const resolution = catalog.lookup(value);\n if (resolution === undefined) {\n return {\n code: DiagnosticCode.IconNotVerified,\n severity: DiagnosticSeverity.Warning,\n message: `The catalog of the icon library '${value.library}' is not loaded, so '${value.key}' could not be verified.`,\n ...context,\n };\n }\n\n return resolution.isResolved ? undefined : { code: codes[resolution.diagnostic.kind], severity, message: `${resolution.diagnostic.message}.`, ...context };\n}\n\n/**\n * Checks the icon fields of collection items.\n *\n * @param itemDescriptor What the items look like.\n * @param items The items, each with its id and field values.\n */\nexport function iconProblemsOfItems(\n catalog: EffectiveIconCatalog,\n itemDescriptor: CollectionItemDescriptor | undefined,\n items: { id: string; values: Record<string, unknown>; instance?: string }[],\n severity: DiagnosticSeverity,\n context: DiagnosticContext\n): SceneDiagnostic[] {\n const iconFields = (itemDescriptor?.properties ?? []).filter((field) => field.valueType === PropertyValueType.Icon);\n return items.flatMap((item) =>\n iconFields.flatMap((field) => {\n const problem = iconProblem(catalog, item.values[field.path], severity, { ...context, itemId: item.id, ...(item.instance === undefined ? {} : { instance: item.instance }) });\n return problem ? [{ ...problem, message: `'${field.label}' of '${item.id}': ${problem.message}` }] : [];\n })\n );\n}\n\n/**\n * Checks a property's value - an icon, or a collection whose items have icon fields - against the effective icon\n * catalog. Any other kind of property has nothing to check.\n *\n * @param descriptor The property.\n * @param value The value; for a collection, the flat items (`{ id, ...fields }`) as they are stored.\n */\nexport function iconProblemsOfProperty(catalog: EffectiveIconCatalog, descriptor: PropertyDescriptor, value: unknown, severity: DiagnosticSeverity, context: DiagnosticContext): SceneDiagnostic[] {\n if (descriptor.valueType === PropertyValueType.Icon) {\n const problem = iconProblem(catalog, value, severity, { ...context, path: descriptor.path });\n return problem ? [{ ...problem, message: `'${descriptor.label}': ${problem.message}` }] : [];\n }\n\n if (descriptor.valueType === PropertyValueType.Collection && Array.isArray(value)) {\n const items = value\n .filter((item): item is Record<string, unknown> => item !== null && typeof item === 'object')\n .map(({ id, ...values }) => ({ id: String(id), values }));\n return iconProblemsOfItems(catalog, descriptor.item, items, severity, { ...context, path: descriptor.path });\n }\n\n if (descriptor.valueType === PropertyValueType.Object && descriptor.properties !== undefined && value !== null && typeof value === 'object' && !Array.isArray(value)) {\n const record = value as Record<string, unknown>;\n return descriptor.properties.flatMap((field) =>\n iconProblemsOfProperty(catalog, { ...field, path: `${descriptor.path}.${field.path}` }, record[field.path], severity, context));\n }\n\n return [];\n}\n"],"names":["codes","DiagnosticCode","MissingIconLibrary","MissingIcon","MissingIconVariant","IncompatibleIconLibrary","IconCatalogUnavailable","iconProblem","catalog","value","severity","context","isIconReference","undefined","resolution","lookup","code","IconNotVerified","DiagnosticSeverity","Warning","message","library","key","isResolved","diagnostic","kind","iconProblemsOfItems","itemDescriptor","items","iconFields","properties","filter","field","valueType","PropertyValueType","Icon","flatMap","item","problem","values","path","itemId","id","instance","label","iconProblemsOfProperty","descriptor","Collection","Array","isArray","map","String","Object","record"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateValue.d.ts","sourceRoot":"","sources":["../../../editing/validateValue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,wBAAwB,EAAE,kBAAkB,EAAqB,MAAM,qBAAqB,CAAC;AAiBzH,wBAAgB,aAAa,CAAC,UAAU,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"validateValue.d.ts","sourceRoot":"","sources":["../../../editing/validateValue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,wBAAwB,EAAE,kBAAkB,EAAqB,MAAM,qBAAqB,CAAC;AAiBzH,wBAAgB,aAAa,CAAC,UAAU,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CA+DhG;AAwED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB;AASD,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,wBAAwB,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,EAAE,CAE5I"}
|
|
@@ -56,6 +56,8 @@ function isNonEmptyString(value) {
|
|
|
56
56
|
return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';
|
|
57
57
|
case PropertyValueType.Collection:
|
|
58
58
|
return validateCollection(descriptor, value);
|
|
59
|
+
case PropertyValueType.Object:
|
|
60
|
+
return validateObject(descriptor, value);
|
|
59
61
|
case PropertyValueType.Json:
|
|
60
62
|
return isJsonValue(value) ? undefined : 'expected a JSON value';
|
|
61
63
|
default:
|
|
@@ -96,6 +98,12 @@ const maximumJsonDepth = 64;
|
|
|
96
98
|
parents.delete(value);
|
|
97
99
|
return valid;
|
|
98
100
|
}
|
|
101
|
+
function validateObject(descriptor, value) {
|
|
102
|
+
if (descriptor.properties === undefined) return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';
|
|
103
|
+
if (!isRecord(value)) return 'expected a structured value';
|
|
104
|
+
const problem = validateFields(descriptor.properties, value, 'this object').at(0);
|
|
105
|
+
return problem ? `${problem.field} ${problem.problem}` : undefined;
|
|
106
|
+
}
|
|
99
107
|
function validateCollection(descriptor, value) {
|
|
100
108
|
if (!Array.isArray(value)) return 'expected a list';
|
|
101
109
|
const constraints = descriptor.constraints ?? {};
|
|
@@ -119,14 +127,16 @@ function validateCollection(descriptor, value) {
|
|
|
119
127
|
* @param values The item's field values, keyed by field path.
|
|
120
128
|
* @returns Every field that is unknown or has an unacceptable value.
|
|
121
129
|
*/ function validateItemValues(itemDescriptor, values) {
|
|
122
|
-
|
|
130
|
+
return validateFields(itemDescriptor?.properties ?? [], values, 'this collection\'s items');
|
|
131
|
+
}
|
|
132
|
+
function validateFields(fields, values, owner) {
|
|
123
133
|
const problems = [];
|
|
124
134
|
for (const [field, fieldValue] of Object.entries(values)){
|
|
125
135
|
const fieldDescriptor = fields.find((candidate)=>candidate.path === field);
|
|
126
136
|
if (!fieldDescriptor) {
|
|
127
137
|
problems.push({
|
|
128
138
|
field,
|
|
129
|
-
problem:
|
|
139
|
+
problem: `is not a field of ${owner}`
|
|
130
140
|
});
|
|
131
141
|
continue;
|
|
132
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateValue.js","sources":["../../../editing/validateValue.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingSourceKind, CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * Checks a value against a property descriptor.\n *\n * @param descriptor The property the value is for.\n * @param value The value to check. `undefined` means \"not set\", which is fine unless the property is required.\n * @returns The reason the value is not acceptable, or `undefined` when it is.\n */\nexport function validateValue(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n const constraints = descriptor.constraints ?? {};\n if (value === undefined || value === null) {\n return constraints.required ? 'a value is required' : undefined;\n }\n\n const binding = bindingKindOf(value);\n if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {\n return descriptor.acceptedBindingKinds.includes(binding.kind)\n ? undefined\n : `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;\n }\n\n switch (descriptor.valueType) {\n case PropertyValueType.String: {\n if (typeof value !== 'string') return 'expected a string';\n if (constraints.minimumLength !== undefined && value.length < constraints.minimumLength) return `must be at least ${constraints.minimumLength} characters`;\n if (constraints.maximumLength !== undefined && value.length > constraints.maximumLength) return `must be at most ${constraints.maximumLength} characters`;\n if (constraints.pattern !== undefined && !new RegExp(`^(?:${constraints.pattern})$`).test(value)) return `must match ${constraints.pattern}`;\n return undefined;\n }\n\n case PropertyValueType.Number: {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 'expected a number';\n if (constraints.integer && !Number.isInteger(value)) return 'expected a whole number';\n if (constraints.minimum !== undefined && value < constraints.minimum) return `must be at least ${constraints.minimum}`;\n if (constraints.maximum !== undefined && value > constraints.maximum) return `must be at most ${constraints.maximum}`;\n return undefined;\n }\n\n case PropertyValueType.Boolean:\n return typeof value === 'boolean' ? undefined : 'expected true or false';\n\n case PropertyValueType.Enum:\n return (descriptor.choices ?? []).some(choice => choice.value === value) ? undefined : 'not one of the allowed choices';\n\n case PropertyValueType.Icon:\n if (!isRecord(value) || !isNonEmptyString(value.library) || !isNonEmptyString(value.key)) return 'expected an icon reference with a library and a key';\n return value.variant === undefined || typeof value.variant === 'string' ? undefined : 'the icon variant must be a string';\n\n case PropertyValueType.Destination:\n if (!isRecord(value) || !isNonEmptyString(value.screen)) return 'expected a destination naming a screen';\n return value.routeParameterBindings === undefined || isRecord(value.routeParameterBindings)\n ? undefined\n : 'routeParameterBindings must be an object';\n\n case PropertyValueType.QueryReference:\n if (isNonEmptyString(value)) return undefined;\n if (!isRecord(value) || !isNonEmptyString(value.queryId) || !isNonEmptyString(value.query)) return 'expected a query name or a query binding';\n return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';\n\n case PropertyValueType.Collection:\n return validateCollection(descriptor, value);\n\n case PropertyValueType.Json:\n return isJsonValue(value) ? undefined : 'expected a JSON value';\n\n default:\n return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';\n }\n}\n\n/**\n * The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;\n * the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.\n */\nconst bindingKinds = new Set<string>(Object.values(BindingSourceKind));\n\n/**\n * The source kind of a value that is a typed binding expression - an object with a known `kind` and a\n * string `path` - rather than a value of the property's own type. Only consulted for properties that declare\n * `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a\n * table's `selectedItem` instead of listing its items.\n */\nfunction bindingKindOf(value: unknown): { kind: BindingSourceKind } | undefined {\n if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;\n return { kind: value.kind as BindingSourceKind };\n}\n\nconst maximumJsonDepth = 64;\n\n/**\n * Whether a value is JSON: `null`, a string, a boolean, a finite number, or an array or plain object of those.\n * The value is only inspected, never serialized, so what an editor stores is exactly what was passed in.\n */\nfunction isJsonValue(value: unknown, parents = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || parents.has(value) || parents.size >= maximumJsonDepth) return false;\n\n const isArray = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (isArray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) return false;\n\n parents.add(value);\n const values = isArray ? Array.from({ length: value.length }, (_, index) => (index in value ? value[index] : undefined)) : Object.values(value);\n const valid = values.every(candidate => isJsonValue(candidate, parents));\n parents.delete(value);\n return valid;\n}\n\nfunction validateCollection(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n if (!Array.isArray(value)) return 'expected a list';\n const constraints = descriptor.constraints ?? {};\n if (constraints.minimumItems !== undefined && value.length < constraints.minimumItems) return `needs at least ${constraints.minimumItems} items`;\n if (constraints.maximumItems !== undefined && value.length > constraints.maximumItems) return `allows at most ${constraints.maximumItems} items`;\n\n const identities = new Set<string>();\n for (const item of value) {\n if (!isRecord(item) || !isNonEmptyString(item.id)) return 'every item needs an id';\n if (identities.has(item.id)) return `the item id '${item.id}' is used twice`;\n identities.add(item.id);\n\n const { id: _identity, ...values } = item;\n const problem = validateItemValues(descriptor.item, values).at(0);\n if (problem) return `item '${item.id}': ${problem.field} ${problem.problem}`;\n }\n\n return undefined;\n}\n\n/**\n * One field of a collection item that does not fit its descriptor.\n */\nexport interface ItemFieldProblem {\n field: string;\n problem: string;\n}\n\n/**\n * Checks a collection item's field values against the collection's item descriptor.\n *\n * @param itemDescriptor What the items look like.\n * @param values The item's field values, keyed by field path.\n * @returns Every field that is unknown or has an unacceptable value.\n */\nexport function validateItemValues(itemDescriptor: CollectionItemDescriptor | undefined, values: Record<string, unknown>): ItemFieldProblem[] {\n const fields = itemDescriptor?.properties ?? [];\n const problems: ItemFieldProblem[] = [];\n\n for (const [field, fieldValue] of Object.entries(values)) {\n const fieldDescriptor = fields.find(candidate => candidate.path === field);\n if (!fieldDescriptor) {\n problems.push({ field, problem: 'is not a field of this collection\\'s items' });\n continue;\n }\n\n const problem = validateValue(fieldDescriptor, fieldValue);\n if (problem) problems.push({ field, problem });\n }\n\n for (const fieldDescriptor of fields) {\n if (fieldDescriptor.constraints?.required && values[fieldDescriptor.path] === undefined) {\n problems.push({ field: fieldDescriptor.path, problem: 'a value is required' });\n }\n }\n\n return problems;\n}\n"],"names":["isRecord","value","Array","isArray","isNonEmptyString","length","validateValue","descriptor","constraints","undefined","required","binding","bindingKindOf","acceptedBindingKinds","includes","kind","join","valueType","PropertyValueType","String","minimumLength","maximumLength","pattern","RegExp","test","Number","isFinite","integer","isInteger","minimum","maximum","Boolean","Enum","choices","some","choice","Icon","library","key","variant","Destination","screen","routeParameterBindings","QueryReference","queryId","query","arguments","results","Collection","validateCollection","Json","isJsonValue","bindingKinds","Set","Object","values","BindingSourceKind","has","path","maximumJsonDepth","parents","size","prototype","getPrototypeOf","add","from","_","index","valid","every","candidate","delete","minimumItems","maximumItems","identities","item","id","_identity","problem","validateItemValues","at","field","itemDescriptor","fields","properties","problems","fieldValue","entries","fieldDescriptor","find","push"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validateValue.js","sources":["../../../editing/validateValue.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingSourceKind, CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * Checks a value against a property descriptor.\n *\n * @param descriptor The property the value is for.\n * @param value The value to check. `undefined` means \"not set\", which is fine unless the property is required.\n * @returns The reason the value is not acceptable, or `undefined` when it is.\n */\nexport function validateValue(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n const constraints = descriptor.constraints ?? {};\n if (value === undefined || value === null) {\n return constraints.required ? 'a value is required' : undefined;\n }\n\n const binding = bindingKindOf(value);\n if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {\n return descriptor.acceptedBindingKinds.includes(binding.kind)\n ? undefined\n : `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;\n }\n\n switch (descriptor.valueType) {\n case PropertyValueType.String: {\n if (typeof value !== 'string') return 'expected a string';\n if (constraints.minimumLength !== undefined && value.length < constraints.minimumLength) return `must be at least ${constraints.minimumLength} characters`;\n if (constraints.maximumLength !== undefined && value.length > constraints.maximumLength) return `must be at most ${constraints.maximumLength} characters`;\n if (constraints.pattern !== undefined && !new RegExp(`^(?:${constraints.pattern})$`).test(value)) return `must match ${constraints.pattern}`;\n return undefined;\n }\n\n case PropertyValueType.Number: {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 'expected a number';\n if (constraints.integer && !Number.isInteger(value)) return 'expected a whole number';\n if (constraints.minimum !== undefined && value < constraints.minimum) return `must be at least ${constraints.minimum}`;\n if (constraints.maximum !== undefined && value > constraints.maximum) return `must be at most ${constraints.maximum}`;\n return undefined;\n }\n\n case PropertyValueType.Boolean:\n return typeof value === 'boolean' ? undefined : 'expected true or false';\n\n case PropertyValueType.Enum:\n return (descriptor.choices ?? []).some(choice => choice.value === value) ? undefined : 'not one of the allowed choices';\n\n case PropertyValueType.Icon:\n if (!isRecord(value) || !isNonEmptyString(value.library) || !isNonEmptyString(value.key)) return 'expected an icon reference with a library and a key';\n return value.variant === undefined || typeof value.variant === 'string' ? undefined : 'the icon variant must be a string';\n\n case PropertyValueType.Destination:\n if (!isRecord(value) || !isNonEmptyString(value.screen)) return 'expected a destination naming a screen';\n return value.routeParameterBindings === undefined || isRecord(value.routeParameterBindings)\n ? undefined\n : 'routeParameterBindings must be an object';\n\n case PropertyValueType.QueryReference:\n if (isNonEmptyString(value)) return undefined;\n if (!isRecord(value) || !isNonEmptyString(value.queryId) || !isNonEmptyString(value.query)) return 'expected a query name or a query binding';\n return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';\n\n case PropertyValueType.Collection:\n return validateCollection(descriptor, value);\n\n case PropertyValueType.Object:\n return validateObject(descriptor, value);\n\n case PropertyValueType.Json:\n return isJsonValue(value) ? undefined : 'expected a JSON value';\n\n default:\n return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';\n }\n}\n\n/**\n * The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;\n * the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.\n */\nconst bindingKinds = new Set<string>(Object.values(BindingSourceKind));\n\n/**\n * The source kind of a value that is a typed binding expression - an object with a known `kind` and a\n * string `path` - rather than a value of the property's own type. Only consulted for properties that declare\n * `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a\n * table's `selectedItem` instead of listing its items.\n */\nfunction bindingKindOf(value: unknown): { kind: BindingSourceKind } | undefined {\n if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;\n return { kind: value.kind as BindingSourceKind };\n}\n\nconst maximumJsonDepth = 64;\n\n/**\n * Whether a value is JSON: `null`, a string, a boolean, a finite number, or an array or plain object of those.\n * The value is only inspected, never serialized, so what an editor stores is exactly what was passed in.\n */\nfunction isJsonValue(value: unknown, parents = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || parents.has(value) || parents.size >= maximumJsonDepth) return false;\n\n const isArray = Array.isArray(value);\n const prototype = Object.getPrototypeOf(value);\n if (isArray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) return false;\n\n parents.add(value);\n const values = isArray ? Array.from({ length: value.length }, (_, index) => (index in value ? value[index] : undefined)) : Object.values(value);\n const valid = values.every(candidate => isJsonValue(candidate, parents));\n parents.delete(value);\n return valid;\n}\n\nfunction validateObject(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n if (descriptor.properties === undefined) return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';\n if (!isRecord(value)) return 'expected a structured value';\n\n const problem = validateFields(descriptor.properties, value, 'this object').at(0);\n return problem ? `${problem.field} ${problem.problem}` : undefined;\n}\n\nfunction validateCollection(descriptor: PropertyDescriptor, value: unknown): string | undefined {\n if (!Array.isArray(value)) return 'expected a list';\n const constraints = descriptor.constraints ?? {};\n if (constraints.minimumItems !== undefined && value.length < constraints.minimumItems) return `needs at least ${constraints.minimumItems} items`;\n if (constraints.maximumItems !== undefined && value.length > constraints.maximumItems) return `allows at most ${constraints.maximumItems} items`;\n\n const identities = new Set<string>();\n for (const item of value) {\n if (!isRecord(item) || !isNonEmptyString(item.id)) return 'every item needs an id';\n if (identities.has(item.id)) return `the item id '${item.id}' is used twice`;\n identities.add(item.id);\n\n const { id: _identity, ...values } = item;\n const problem = validateItemValues(descriptor.item, values).at(0);\n if (problem) return `item '${item.id}': ${problem.field} ${problem.problem}`;\n }\n\n return undefined;\n}\n\n/**\n * One field of a collection item that does not fit its descriptor.\n */\nexport interface ItemFieldProblem {\n field: string;\n problem: string;\n}\n\n/**\n * Checks a collection item's field values against the collection's item descriptor.\n *\n * @param itemDescriptor What the items look like.\n * @param values The item's field values, keyed by field path.\n * @returns Every field that is unknown or has an unacceptable value.\n */\nexport function validateItemValues(itemDescriptor: CollectionItemDescriptor | undefined, values: Record<string, unknown>): ItemFieldProblem[] {\n return validateFields(itemDescriptor?.properties ?? [], values, 'this collection\\'s items');\n}\n\nfunction validateFields(fields: PropertyDescriptor[], values: Record<string, unknown>, owner: string): ItemFieldProblem[] {\n const problems: ItemFieldProblem[] = [];\n\n for (const [field, fieldValue] of Object.entries(values)) {\n const fieldDescriptor = fields.find(candidate => candidate.path === field);\n if (!fieldDescriptor) {\n problems.push({ field, problem: `is not a field of ${owner}` });\n continue;\n }\n\n const problem = validateValue(fieldDescriptor, fieldValue);\n if (problem) problems.push({ field, problem });\n }\n\n for (const fieldDescriptor of fields) {\n if (fieldDescriptor.constraints?.required && values[fieldDescriptor.path] === undefined) {\n problems.push({ field: fieldDescriptor.path, problem: 'a value is required' });\n }\n }\n\n return problems;\n}\n"],"names":["isRecord","value","Array","isArray","isNonEmptyString","length","validateValue","descriptor","constraints","undefined","required","binding","bindingKindOf","acceptedBindingKinds","includes","kind","join","valueType","PropertyValueType","String","minimumLength","maximumLength","pattern","RegExp","test","Number","isFinite","integer","isInteger","minimum","maximum","Boolean","Enum","choices","some","choice","Icon","library","key","variant","Destination","screen","routeParameterBindings","QueryReference","queryId","query","arguments","results","Collection","validateCollection","Object","validateObject","Json","isJsonValue","bindingKinds","Set","values","BindingSourceKind","has","path","maximumJsonDepth","parents","size","prototype","getPrototypeOf","add","from","_","index","valid","every","candidate","delete","properties","problem","validateFields","at","field","minimumItems","maximumItems","identities","item","id","_identity","validateItemValues","itemDescriptor","fields","owner","problems","fieldValue","entries","fieldDescriptor","find","push"],"mappings":"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"}
|