@cratis/scene.engine 4.15.0 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -158,6 +158,17 @@ function collectionValue(grant, matching, instance, items, diagnostics$1) {
158
158
  scalarValue(effectiveGrant, matching, instance, current, diagnostics$1);
159
159
  }
160
160
  }
161
+ const maximumItems = grant.descriptor.constraints?.maximumItems;
162
+ if (isCollection && maximumItems !== undefined && items.length > maximumItems) {
163
+ // Saved items that no longer fit - the owner lowered the limit after they were added - are left out of
164
+ // the result in order and kept in the saved data, like any other saved value that no longer fits.
165
+ const dropped = items.splice(maximumItems);
166
+ diagnostics$1.push(diagnostics.errorDiagnostic(scene_model.DiagnosticCode.ContributionTypeMismatch, `'${grant.path}' on '${grant.component}' allows at most ${maximumItems} items; ${dropped.map((item)=>`'${item.id}'`).join(', ')} ${dropped.length === 1 ? 'is' : 'are'} ignored and kept.`, {
167
+ instance: current.contributedBy ?? owner.instance,
168
+ component: grant.component,
169
+ path: grant.path
170
+ }));
171
+ }
161
172
  if (isCollection) {
162
173
  current.items = items;
163
174
  current.inheritedValue = baseItems.map(toFlatItem);
@@ -1 +1 @@
1
- {"version":3,"file":"resolveEffectiveConfiguration.js","sources":["../../../editing/resolveEffectiveConfiguration.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 {\n CollectionOperation, DiagnosticCode, EffectiveCollectionItem, EffectiveComponentConfiguration,\n EffectiveConfiguration, EffectivePropertyValue, InstanceContribution, PropertyValueType, SceneDiagnostic, ValueSource,\n} from '@cratis/scene.model';\nimport { DescriptorCatalog, findComponentDescriptor } from './DescriptorCatalog';\nimport { errorDiagnostic } from './diagnostics';\nimport { computeExposureGrants, ExposureGrant, grantKey } from './exposureGrants';\nimport { cloneData, getValueAtPath, setValueAtPath } from './pathAccess';\nimport { TemplateChain } from './TemplateChain';\nimport { validateItemValues, validateValue } from './validateValue';\n\n/**\n * Splits a flat collection item as it is stored on an element - `{ id, label, ... }` - into its id and fields.\n */\nfunction toEffectiveItem(item: unknown, index: number): EffectiveCollectionItem {\n const { id, ...values } = (item !== null && typeof item === 'object' ? item : {}) as Record<string, unknown>;\n return { id: typeof id === 'string' && id.length > 0 ? id : `owner-${index}`, values, origin: 'owner', fixed: true };\n}\n\nfunction toFlatItem(item: EffectiveCollectionItem): Record<string, unknown> {\n return { id: item.id, ...item.values };\n}\n\nfunction scalarValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, current: EffectivePropertyValue, diagnostics: SceneDiagnostic[]): void {\n for (const contribution of matching) {\n const problem = contribution.value === undefined ? 'a value is required' : validateValue(grant.descriptor, contribution.value);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTypeMismatch,\n `The saved value of '${grant.path}' set by '${instance}' is ignored: ${problem}. It is kept, and applies again when it fits.`,\n { instance, component: grant.component, path: grant.path }));\n continue;\n }\n\n current.value = contribution.value;\n current.source = ValueSource.Instance;\n current.contributedBy = instance;\n }\n}\n\nfunction collectionValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, items: EffectiveCollectionItem[], diagnostics: SceneDiagnostic[]): boolean {\n let contributed = false;\n\n for (const contribution of matching) {\n const context = { instance, component: grant.component, path: grant.path };\n if (contribution.items === undefined) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionTypeMismatch, `The saved value of '${grant.path}' set by '${instance}' is ignored: a collection takes items.`, context));\n continue;\n }\n\n if (contribution.items.length > 0 && !grant.operations.includes(CollectionOperation.Add)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionOperationNotPermitted,\n `'${instance}' has items in '${grant.path}', but adding items is not exposed. They are ignored and kept.`,\n context));\n continue;\n }\n\n for (const item of contribution.items) {\n const itemContext = { ...context, itemId: item.id };\n if (items.some(existing => existing.id === item.id)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.DuplicateCollectionItem, `The item id '${item.id}' in '${grant.path}' is already used.`, itemContext));\n continue;\n }\n\n const values: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(item.values)) {\n if (grant.editableFields !== undefined && !grant.editableFields.includes(field)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionOperationNotPermitted, `The field '${field}' of '${grant.path}' is not exposed for editing.`, itemContext));\n continue;\n }\n\n const problem = validateItemValues(grant.descriptor.item, { [field]: value }).find(candidate => candidate.field === field);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n problem.problem.startsWith('is not a field') ? DiagnosticCode.UnknownCollectionField : DiagnosticCode.ContributionTypeMismatch,\n `The field '${field}' of an item in '${grant.path}' is ignored: ${problem.problem}.`,\n itemContext));\n continue;\n }\n\n values[field] = value;\n }\n\n items.push({ id: item.id, values, origin: instance, fixed: false });\n contributed = true;\n }\n }\n\n return contributed;\n}\n\n/**\n * Resolves what every configurable component in a template chain is worth: the owner's own values, with each\n * instance's contributions applied in nesting order.\n *\n * This is the one merge. The editor shows its result and the runtime renders from it, so what an author sees is\n * what Play renders. Order is fixed: the owner's value first, then each level from the outermost inwards, so a\n * later level wins a scalar and appends to a collection after the earlier ones.\n *\n * Nothing in the persisted data is changed. A contribution that cannot apply - the exposure was withdrawn, the\n * property's type changed, the component is gone - is reported in `diagnostics` and left out of the result, and\n * stays in `instanceContributions`, so restoring the exposure brings its value back.\n *\n * @param templateChain The nesting, from {@link resolveTemplateChain} or built by hand.\n * @param instanceContributions What each instance has set.\n * @param catalog The descriptors saying what each component supports.\n */\nexport function resolveEffectiveConfiguration(\n templateChain: TemplateChain,\n instanceContributions: InstanceContribution[],\n catalog: DescriptorCatalog,\n): EffectiveConfiguration {\n const grants = computeExposureGrants(templateChain, catalog);\n const diagnostics: SceneDiagnostic[] = [...templateChain.diagnostics, ...grants.diagnostics];\n const handled = new Set<InstanceContribution>();\n const components = new Map<string, EffectiveComponentConfiguration>();\n\n for (const grant of grants.exposed) {\n const owner = templateChain.levels[grant.ownerLevel];\n const element = owner.elements.find(candidate => candidate.id === grant.component)!;\n\n let configuration = components.get(grant.component);\n if (!configuration) {\n configuration = { component: grant.component, owner: owner.owner, properties: cloneData(element.properties), values: [] };\n components.set(grant.component, configuration);\n }\n\n const stored = getValueAtPath(element.properties, grant.path);\n const base = stored === undefined ? cloneData(grant.descriptor.default) : cloneData(stored);\n const isCollection = grant.descriptor.valueType === PropertyValueType.Collection;\n const baseItems = isCollection && Array.isArray(base) ? base.map(toEffectiveItem) : [];\n const items = [...baseItems];\n\n const current: EffectivePropertyValue = {\n path: grant.path,\n value: base,\n source: stored === undefined ? ValueSource.Default : ValueSource.Local,\n inheritedValue: base,\n };\n let contributed = false;\n\n for (let index = grant.ownerLevel + 1; index < templateChain.levels.length; index++) {\n const instance = templateChain.levels[index].instance;\n if (!grants.byInstance.get(instance)?.has(grantKey(grant.component, grant.path))) continue;\n\n const effectiveGrant = grants.byInstance.get(instance)!.get(grantKey(grant.component, grant.path))!;\n const matching = instanceContributions.filter(contribution =>\n contribution.instance === instance && contribution.component === grant.component && contribution.path === grant.path);\n for (const contribution of matching) handled.add(contribution);\n\n if (isCollection) {\n if (collectionValue(effectiveGrant, matching, instance, items, diagnostics)) {\n contributed = true;\n current.contributedBy = instance;\n }\n } else {\n scalarValue(effectiveGrant, matching, instance, current, diagnostics);\n }\n }\n\n if (isCollection) {\n current.items = items;\n current.inheritedValue = baseItems.map(toFlatItem);\n current.value = items.map(toFlatItem);\n if (contributed) current.source = ValueSource.Instance;\n }\n\n if (current.value !== undefined) setValueAtPath(configuration.properties, grant.path, current.value);\n configuration.values.push(current);\n }\n\n const levelOf = new Map(templateChain.levels.map((chainLevel, index) => [chainLevel.instance, index]));\n for (const contribution of instanceContributions) {\n const contributorLevel = levelOf.get(contribution.instance);\n if (contributorLevel === undefined || handled.has(contribution)) continue;\n\n const context = { instance: contribution.instance, component: contribution.component, path: contribution.path };\n const owner = templateChain.levels.slice(0, contributorLevel).find(chainLevel => chainLevel.elements.some(element => element.id === contribution.component));\n if (!owner) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTargetMissing,\n `'${contribution.instance}' has saved values for '${contribution.component}', which is not in any layout or template above it. They are kept.`,\n context));\n } else if (!findComponentDescriptor(catalog, owner.elements.find(element => element.id === contribution.component)!.componentName)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.MissingComponentDescriptor,\n `'${contribution.instance}' has saved values for '${contribution.component}', but nothing describes that component any more. They are kept.`,\n context));\n } else {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionNotExposed,\n `'${contribution.instance}' has a saved value for '${contribution.path}' on '${contribution.component}', which is not exposed to it. It is ignored and kept.`,\n context));\n }\n }\n\n return { components: [...components.values()], diagnostics };\n}\n"],"names":["toEffectiveItem","item","index","id","values","length","origin","fixed","toFlatItem","scalarValue","grant","matching","instance","current","diagnostics","contribution","problem","value","undefined","validateValue","descriptor","push","errorDiagnostic","DiagnosticCode","ContributionTypeMismatch","path","component","source","ValueSource","Instance","contributedBy","collectionValue","items","contributed","context","operations","includes","CollectionOperation","Add","ContributionOperationNotPermitted","itemContext","itemId","some","existing","DuplicateCollectionItem","field","Object","entries","editableFields","validateItemValues","find","candidate","startsWith","UnknownCollectionField","resolveEffectiveConfiguration","templateChain","instanceContributions","catalog","grants","computeExposureGrants","handled","Set","components","Map","exposed","owner","levels","ownerLevel","element","elements","configuration","get","properties","cloneData","set","stored","getValueAtPath","base","default","isCollection","valueType","PropertyValueType","Collection","baseItems","Array","isArray","map","Default","Local","inheritedValue","byInstance","has","grantKey","effectiveGrant","filter","add","setValueAtPath","levelOf","chainLevel","contributorLevel","slice","ContributionTargetMissing","findComponentDescriptor","componentName","MissingComponentDescriptor","ContributionNotExposed"],"mappings":"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"}
1
+ {"version":3,"file":"resolveEffectiveConfiguration.js","sources":["../../../editing/resolveEffectiveConfiguration.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 {\n CollectionOperation, DiagnosticCode, EffectiveCollectionItem, EffectiveComponentConfiguration,\n EffectiveConfiguration, EffectivePropertyValue, InstanceContribution, PropertyValueType, SceneDiagnostic, ValueSource,\n} from '@cratis/scene.model';\nimport { DescriptorCatalog, findComponentDescriptor } from './DescriptorCatalog';\nimport { errorDiagnostic } from './diagnostics';\nimport { computeExposureGrants, ExposureGrant, grantKey } from './exposureGrants';\nimport { cloneData, getValueAtPath, setValueAtPath } from './pathAccess';\nimport { TemplateChain } from './TemplateChain';\nimport { validateItemValues, validateValue } from './validateValue';\n\n/**\n * Splits a flat collection item as it is stored on an element - `{ id, label, ... }` - into its id and fields.\n */\nfunction toEffectiveItem(item: unknown, index: number): EffectiveCollectionItem {\n const { id, ...values } = (item !== null && typeof item === 'object' ? item : {}) as Record<string, unknown>;\n return { id: typeof id === 'string' && id.length > 0 ? id : `owner-${index}`, values, origin: 'owner', fixed: true };\n}\n\nfunction toFlatItem(item: EffectiveCollectionItem): Record<string, unknown> {\n return { id: item.id, ...item.values };\n}\n\nfunction scalarValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, current: EffectivePropertyValue, diagnostics: SceneDiagnostic[]): void {\n for (const contribution of matching) {\n const problem = contribution.value === undefined ? 'a value is required' : validateValue(grant.descriptor, contribution.value);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTypeMismatch,\n `The saved value of '${grant.path}' set by '${instance}' is ignored: ${problem}. It is kept, and applies again when it fits.`,\n { instance, component: grant.component, path: grant.path }));\n continue;\n }\n\n current.value = contribution.value;\n current.source = ValueSource.Instance;\n current.contributedBy = instance;\n }\n}\n\nfunction collectionValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, items: EffectiveCollectionItem[], diagnostics: SceneDiagnostic[]): boolean {\n let contributed = false;\n\n for (const contribution of matching) {\n const context = { instance, component: grant.component, path: grant.path };\n if (contribution.items === undefined) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionTypeMismatch, `The saved value of '${grant.path}' set by '${instance}' is ignored: a collection takes items.`, context));\n continue;\n }\n\n if (contribution.items.length > 0 && !grant.operations.includes(CollectionOperation.Add)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionOperationNotPermitted,\n `'${instance}' has items in '${grant.path}', but adding items is not exposed. They are ignored and kept.`,\n context));\n continue;\n }\n\n for (const item of contribution.items) {\n const itemContext = { ...context, itemId: item.id };\n if (items.some(existing => existing.id === item.id)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.DuplicateCollectionItem, `The item id '${item.id}' in '${grant.path}' is already used.`, itemContext));\n continue;\n }\n\n const values: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(item.values)) {\n if (grant.editableFields !== undefined && !grant.editableFields.includes(field)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionOperationNotPermitted, `The field '${field}' of '${grant.path}' is not exposed for editing.`, itemContext));\n continue;\n }\n\n const problem = validateItemValues(grant.descriptor.item, { [field]: value }).find(candidate => candidate.field === field);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n problem.problem.startsWith('is not a field') ? DiagnosticCode.UnknownCollectionField : DiagnosticCode.ContributionTypeMismatch,\n `The field '${field}' of an item in '${grant.path}' is ignored: ${problem.problem}.`,\n itemContext));\n continue;\n }\n\n values[field] = value;\n }\n\n items.push({ id: item.id, values, origin: instance, fixed: false });\n contributed = true;\n }\n }\n\n return contributed;\n}\n\n/**\n * Resolves what every configurable component in a template chain is worth: the owner's own values, with each\n * instance's contributions applied in nesting order.\n *\n * This is the one merge. The editor shows its result and the runtime renders from it, so what an author sees is\n * what Play renders. Order is fixed: the owner's value first, then each level from the outermost inwards, so a\n * later level wins a scalar and appends to a collection after the earlier ones.\n *\n * Nothing in the persisted data is changed. A contribution that cannot apply - the exposure was withdrawn, the\n * property's type changed, the component is gone - is reported in `diagnostics` and left out of the result, and\n * stays in `instanceContributions`, so restoring the exposure brings its value back.\n *\n * @param templateChain The nesting, from {@link resolveTemplateChain} or built by hand.\n * @param instanceContributions What each instance has set.\n * @param catalog The descriptors saying what each component supports.\n */\nexport function resolveEffectiveConfiguration(\n templateChain: TemplateChain,\n instanceContributions: InstanceContribution[],\n catalog: DescriptorCatalog,\n): EffectiveConfiguration {\n const grants = computeExposureGrants(templateChain, catalog);\n const diagnostics: SceneDiagnostic[] = [...templateChain.diagnostics, ...grants.diagnostics];\n const handled = new Set<InstanceContribution>();\n const components = new Map<string, EffectiveComponentConfiguration>();\n\n for (const grant of grants.exposed) {\n const owner = templateChain.levels[grant.ownerLevel];\n const element = owner.elements.find(candidate => candidate.id === grant.component)!;\n\n let configuration = components.get(grant.component);\n if (!configuration) {\n configuration = { component: grant.component, owner: owner.owner, properties: cloneData(element.properties), values: [] };\n components.set(grant.component, configuration);\n }\n\n const stored = getValueAtPath(element.properties, grant.path);\n const base = stored === undefined ? cloneData(grant.descriptor.default) : cloneData(stored);\n const isCollection = grant.descriptor.valueType === PropertyValueType.Collection;\n const baseItems = isCollection && Array.isArray(base) ? base.map(toEffectiveItem) : [];\n const items = [...baseItems];\n\n const current: EffectivePropertyValue = {\n path: grant.path,\n value: base,\n source: stored === undefined ? ValueSource.Default : ValueSource.Local,\n inheritedValue: base,\n };\n let contributed = false;\n\n for (let index = grant.ownerLevel + 1; index < templateChain.levels.length; index++) {\n const instance = templateChain.levels[index].instance;\n if (!grants.byInstance.get(instance)?.has(grantKey(grant.component, grant.path))) continue;\n\n const effectiveGrant = grants.byInstance.get(instance)!.get(grantKey(grant.component, grant.path))!;\n const matching = instanceContributions.filter(contribution =>\n contribution.instance === instance && contribution.component === grant.component && contribution.path === grant.path);\n for (const contribution of matching) handled.add(contribution);\n\n if (isCollection) {\n if (collectionValue(effectiveGrant, matching, instance, items, diagnostics)) {\n contributed = true;\n current.contributedBy = instance;\n }\n } else {\n scalarValue(effectiveGrant, matching, instance, current, diagnostics);\n }\n }\n\n const maximumItems = grant.descriptor.constraints?.maximumItems;\n if (isCollection && maximumItems !== undefined && items.length > maximumItems) {\n // Saved items that no longer fit - the owner lowered the limit after they were added - are left out of\n // the result in order and kept in the saved data, like any other saved value that no longer fits.\n const dropped = items.splice(maximumItems);\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTypeMismatch,\n `'${grant.path}' on '${grant.component}' allows at most ${maximumItems} items; ${dropped.map(item => `'${item.id}'`).join(', ')} ${dropped.length === 1 ? 'is' : 'are'} ignored and kept.`,\n { instance: current.contributedBy ?? owner.instance, component: grant.component, path: grant.path }));\n }\n\n if (isCollection) {\n current.items = items;\n current.inheritedValue = baseItems.map(toFlatItem);\n current.value = items.map(toFlatItem);\n if (contributed) current.source = ValueSource.Instance;\n }\n\n if (current.value !== undefined) setValueAtPath(configuration.properties, grant.path, current.value);\n configuration.values.push(current);\n }\n\n const levelOf = new Map(templateChain.levels.map((chainLevel, index) => [chainLevel.instance, index]));\n for (const contribution of instanceContributions) {\n const contributorLevel = levelOf.get(contribution.instance);\n if (contributorLevel === undefined || handled.has(contribution)) continue;\n\n const context = { instance: contribution.instance, component: contribution.component, path: contribution.path };\n const owner = templateChain.levels.slice(0, contributorLevel).find(chainLevel => chainLevel.elements.some(element => element.id === contribution.component));\n if (!owner) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTargetMissing,\n `'${contribution.instance}' has saved values for '${contribution.component}', which is not in any layout or template above it. They are kept.`,\n context));\n } else if (!findComponentDescriptor(catalog, owner.elements.find(element => element.id === contribution.component)!.componentName)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.MissingComponentDescriptor,\n `'${contribution.instance}' has saved values for '${contribution.component}', but nothing describes that component any more. They are kept.`,\n context));\n } else {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionNotExposed,\n `'${contribution.instance}' has a saved value for '${contribution.path}' on '${contribution.component}', which is not exposed to it. It is ignored and kept.`,\n context));\n }\n }\n\n return { components: [...components.values()], diagnostics };\n}\n"],"names":["toEffectiveItem","item","index","id","values","length","origin","fixed","toFlatItem","scalarValue","grant","matching","instance","current","diagnostics","contribution","problem","value","undefined","validateValue","descriptor","push","errorDiagnostic","DiagnosticCode","ContributionTypeMismatch","path","component","source","ValueSource","Instance","contributedBy","collectionValue","items","contributed","context","operations","includes","CollectionOperation","Add","ContributionOperationNotPermitted","itemContext","itemId","some","existing","DuplicateCollectionItem","field","Object","entries","editableFields","validateItemValues","find","candidate","startsWith","UnknownCollectionField","resolveEffectiveConfiguration","templateChain","instanceContributions","catalog","grants","computeExposureGrants","handled","Set","components","Map","exposed","owner","levels","ownerLevel","element","elements","configuration","get","properties","cloneData","set","stored","getValueAtPath","base","default","isCollection","valueType","PropertyValueType","Collection","baseItems","Array","isArray","map","Default","Local","inheritedValue","byInstance","has","grantKey","effectiveGrant","filter","add","maximumItems","constraints","dropped","splice","join","setValueAtPath","levelOf","chainLevel","contributorLevel","slice","ContributionTargetMissing","findComponentDescriptor","componentName","MissingComponentDescriptor","ContributionNotExposed"],"mappings":"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"}
@@ -21,6 +21,10 @@ function isNonEmptyString(value) {
21
21
  if (value === undefined || value === null) {
22
22
  return constraints.required ? 'a value is required' : undefined;
23
23
  }
24
+ const binding = bindingKindOf(value);
25
+ if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {
26
+ return descriptor.acceptedBindingKinds.includes(binding.kind) ? undefined : `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;
27
+ }
24
28
  switch(descriptor.valueType){
25
29
  case scene_model.PropertyValueType.String:
26
30
  {
@@ -63,7 +67,19 @@ function isNonEmptyString(value) {
63
67
  /**
64
68
  * The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;
65
69
  * the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.
66
- */ const maximumJsonDepth = 64;
70
+ */ const bindingKinds = new Set(Object.values(scene_model.BindingSourceKind));
71
+ /**
72
+ * The source kind of a value that is a typed binding expression - an object with a known `kind` and a
73
+ * string `path` - rather than a value of the property's own type. Only consulted for properties that declare
74
+ * `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a
75
+ * table's `selectedItem` instead of listing its items.
76
+ */ function bindingKindOf(value) {
77
+ if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;
78
+ return {
79
+ kind: value.kind
80
+ };
81
+ }
82
+ const maximumJsonDepth = 64;
67
83
  /**
68
84
  * Whether a value is JSON: `null`, a string, a boolean, a finite number, or an array or plain object of those.
69
85
  * The value is only inspected, never serialized, so what an editor stores is exactly what was passed in.
@@ -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 { 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 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 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","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","maximumJsonDepth","parents","Set","has","size","prototype","Object","getPrototypeOf","add","values","from","_","index","valid","every","candidate","delete","minimumItems","maximumItems","identities","item","id","_identity","problem","validateItemValues","at","field","itemDescriptor","fields","properties","problems","fieldValue","entries","fieldDescriptor","find","path","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.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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"}
package/dist/cjs/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var resolveBindingExpression = require('./resolveBindingExpression.js');
4
4
  var nestBindingScope = require('./nestBindingScope.js');
5
+ var resolveArgumentSource = require('./resolveArgumentSource.js');
5
6
  var removeComponentOutputs = require('./removeComponentOutputs.js');
6
7
  var QueryBindingState = require('./QueryBindingState.js');
7
8
  var validateBindingExpression = require('./validateBindingExpression.js');
@@ -76,6 +77,8 @@ var collectIconUsages = require('./editing/collectIconUsages.js');
76
77
  exports.createBindingResolver = resolveBindingExpression.createBindingResolver;
77
78
  exports.resolveBindingExpression = resolveBindingExpression.resolveBindingExpression;
78
79
  exports.nestBindingScope = nestBindingScope.nestBindingScope;
80
+ exports.componentArgumentSourcePrefix = resolveArgumentSource.componentArgumentSourcePrefix;
81
+ exports.resolveArgumentSource = resolveArgumentSource.resolveArgumentSource;
79
82
  exports.removeComponentOutputs = removeComponentOutputs.removeComponentOutputs;
80
83
  exports.QueryBindingState = QueryBindingState.QueryBindingState;
81
84
  exports.validateBindingExpression = validateBindingExpression.validateBindingExpression;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var scene_model = require('@cratis/scene.model');
4
+ var resolveBindingExpression = require('./resolveBindingExpression.js');
5
+
6
+ // Copyright (c) Cratis. All rights reserved.
7
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8
+ /** The prefix of an argument source that reads another element's output. */ const componentArgumentSourcePrefix = 'component.';
9
+ /**
10
+ * Resolves where a command argument comes from, as an action's argument mapping writes it.
11
+ *
12
+ * `component.<id>.<output>` reads an output another element publishes - an input's `value`, a table's
13
+ * `selectedItem.id` - from the same output scope a `componentProperty` binding reads. Element ids may contain
14
+ * dots, so the longest id with outputs in scope wins: `component.order.lines.value` reads `value` of
15
+ * `order.lines` when that element exists. Any other source is a path in the data context. An empty source,
16
+ * or an element with no outputs in scope, resolves as absent.
17
+ *
18
+ * The C# engine (`ArgumentSources.Resolve`) behaves identically; both run `argument-source-fixtures.json`.
19
+ */ function resolveArgumentSource(source, scope) {
20
+ if (!source) return undefined;
21
+ if (!source.startsWith(componentArgumentSourcePrefix)) return resolveBindingExpression.resolveBindingExpression({
22
+ path: source
23
+ }, scope);
24
+ const reference = source.substring(componentArgumentSourcePrefix.length);
25
+ const componentId = Object.keys(scope.componentOutputs ?? {}).filter((id)=>reference === id || reference.startsWith(`${id}.`)).sort((left, right)=>right.length - left.length)[0];
26
+ if (componentId === undefined) return undefined;
27
+ return resolveBindingExpression.resolveBindingExpression({
28
+ kind: scene_model.BindingSourceKind.ComponentProperty,
29
+ componentId,
30
+ path: reference.substring(componentId.length + 1)
31
+ }, scope);
32
+ }
33
+
34
+ exports.componentArgumentSourcePrefix = componentArgumentSourcePrefix;
35
+ exports.resolveArgumentSource = resolveArgumentSource;
36
+ //# sourceMappingURL=resolveArgumentSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveArgumentSource.js","sources":["../../resolveArgumentSource.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 } from '@cratis/scene.model';\nimport { BindingScope } from './BindingScope';\nimport { resolveBindingExpression } from './resolveBindingExpression';\n\n/** The prefix of an argument source that reads another element's output. */\nexport const componentArgumentSourcePrefix = 'component.';\n\n/**\n * Resolves where a command argument comes from, as an action's argument mapping writes it.\n *\n * `component.<id>.<output>` reads an output another element publishes - an input's `value`, a table's\n * `selectedItem.id` - from the same output scope a `componentProperty` binding reads. Element ids may contain\n * dots, so the longest id with outputs in scope wins: `component.order.lines.value` reads `value` of\n * `order.lines` when that element exists. Any other source is a path in the data context. An empty source,\n * or an element with no outputs in scope, resolves as absent.\n *\n * The C# engine (`ArgumentSources.Resolve`) behaves identically; both run `argument-source-fixtures.json`.\n */\nexport function resolveArgumentSource(source: string, scope: BindingScope): unknown {\n if (!source) return undefined;\n if (!source.startsWith(componentArgumentSourcePrefix)) return resolveBindingExpression({ path: source }, scope);\n\n const reference = source.substring(componentArgumentSourcePrefix.length);\n const componentId = Object.keys(scope.componentOutputs ?? {})\n .filter(id => reference === id || reference.startsWith(`${id}.`))\n .sort((left, right) => right.length - left.length)[0];\n if (componentId === undefined) return undefined;\n\n return resolveBindingExpression({ kind: BindingSourceKind.ComponentProperty, componentId, path: reference.substring(componentId.length + 1) }, scope);\n}\n"],"names":["componentArgumentSourcePrefix","resolveArgumentSource","source","scope","undefined","startsWith","resolveBindingExpression","path","reference","substring","length","componentId","Object","keys","componentOutputs","filter","id","sort","left","right","kind","BindingSourceKind","ComponentProperty"],"mappings":";;;;;AAAA;AACA;AAMA,6EACO,MAAMA,6BAAAA,GAAgC;AAE7C;;;;;;;;;;AAUC,IACM,SAASC,qBAAAA,CAAsBC,MAAc,EAAEC,KAAmB,EAAA;IACrE,IAAI,CAACD,QAAQ,OAAOE,SAAAA;AACpB,IAAA,IAAI,CAACF,MAAAA,CAAOG,UAAU,CAACL,6BAAAA,CAAAA,EAAgC,OAAOM,iDAAAA,CAAyB;QAAEC,IAAAA,EAAML;KAAO,EAAGC,KAAAA,CAAAA;AAEzG,IAAA,MAAMK,SAAAA,GAAYN,MAAAA,CAAOO,SAAS,CAACT,8BAA8BU,MAAM,CAAA;AACvE,IAAA,MAAMC,WAAAA,GAAcC,MAAAA,CAAOC,IAAI,CAACV,MAAMW,gBAAgB,IAAI,EAAC,CAAA,CACtDC,MAAM,CAACC,CAAAA,EAAAA,GAAMR,SAAAA,KAAcQ,MAAMR,SAAAA,CAAUH,UAAU,CAAC,CAAA,EAAGW,GAAG,CAAC,CAAC,CAAA,CAAA,CAC9DC,IAAI,CAAC,CAACC,IAAAA,EAAMC,KAAAA,GAAUA,KAAAA,CAAMT,MAAM,GAAGQ,IAAAA,CAAKR,MAAM,CAAC,CAAC,CAAA,CAAE;IACzD,IAAIC,WAAAA,KAAgBP,WAAW,OAAOA,SAAAA;AAEtC,IAAA,OAAOE,iDAAAA,CAAyB;AAAEc,QAAAA,IAAAA,EAAMC,8BAAkBC,iBAAiB;AAAEX,QAAAA,WAAAA;AAAaJ,QAAAA,IAAAA,EAAMC,SAAAA,CAAUC,SAAS,CAACE,WAAAA,CAAYD,MAAM,GAAG,CAAA;KAAG,EAAGP,KAAAA,CAAAA;AACnJ;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveEffectiveConfiguration.d.ts","sourceRoot":"","sources":["../../../editing/resolveEffectiveConfiguration.ts"],"names":[],"mappings":"AAGA,OAAO,EAEH,sBAAsB,EAA0B,oBAAoB,EACvE,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAA2B,MAAM,qBAAqB,CAAC;AAIjF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAoGhD,wBAAgB,6BAA6B,CACzC,aAAa,EAAE,aAAa,EAC5B,qBAAqB,EAAE,oBAAoB,EAAE,EAC7C,OAAO,EAAE,iBAAiB,GAC3B,sBAAsB,CAsFxB"}
1
+ {"version":3,"file":"resolveEffectiveConfiguration.d.ts","sourceRoot":"","sources":["../../../editing/resolveEffectiveConfiguration.ts"],"names":[],"mappings":"AAGA,OAAO,EAEH,sBAAsB,EAA0B,oBAAoB,EACvE,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAA2B,MAAM,qBAAqB,CAAC;AAIjF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAoGhD,wBAAgB,6BAA6B,CACzC,aAAa,EAAE,aAAa,EAC5B,qBAAqB,EAAE,oBAAoB,EAAE,EAC7C,OAAO,EAAE,iBAAiB,GAC3B,sBAAsB,CAiGxB"}
@@ -156,6 +156,17 @@ function collectionValue(grant, matching, instance, items, diagnostics) {
156
156
  scalarValue(effectiveGrant, matching, instance, current, diagnostics);
157
157
  }
158
158
  }
159
+ const maximumItems = grant.descriptor.constraints?.maximumItems;
160
+ if (isCollection && maximumItems !== undefined && items.length > maximumItems) {
161
+ // Saved items that no longer fit - the owner lowered the limit after they were added - are left out of
162
+ // the result in order and kept in the saved data, like any other saved value that no longer fits.
163
+ const dropped = items.splice(maximumItems);
164
+ diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionTypeMismatch, `'${grant.path}' on '${grant.component}' allows at most ${maximumItems} items; ${dropped.map((item)=>`'${item.id}'`).join(', ')} ${dropped.length === 1 ? 'is' : 'are'} ignored and kept.`, {
165
+ instance: current.contributedBy ?? owner.instance,
166
+ component: grant.component,
167
+ path: grant.path
168
+ }));
169
+ }
159
170
  if (isCollection) {
160
171
  current.items = items;
161
172
  current.inheritedValue = baseItems.map(toFlatItem);
@@ -1 +1 @@
1
- {"version":3,"file":"resolveEffectiveConfiguration.js","sources":["../../../editing/resolveEffectiveConfiguration.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 {\n CollectionOperation, DiagnosticCode, EffectiveCollectionItem, EffectiveComponentConfiguration,\n EffectiveConfiguration, EffectivePropertyValue, InstanceContribution, PropertyValueType, SceneDiagnostic, ValueSource,\n} from '@cratis/scene.model';\nimport { DescriptorCatalog, findComponentDescriptor } from './DescriptorCatalog';\nimport { errorDiagnostic } from './diagnostics';\nimport { computeExposureGrants, ExposureGrant, grantKey } from './exposureGrants';\nimport { cloneData, getValueAtPath, setValueAtPath } from './pathAccess';\nimport { TemplateChain } from './TemplateChain';\nimport { validateItemValues, validateValue } from './validateValue';\n\n/**\n * Splits a flat collection item as it is stored on an element - `{ id, label, ... }` - into its id and fields.\n */\nfunction toEffectiveItem(item: unknown, index: number): EffectiveCollectionItem {\n const { id, ...values } = (item !== null && typeof item === 'object' ? item : {}) as Record<string, unknown>;\n return { id: typeof id === 'string' && id.length > 0 ? id : `owner-${index}`, values, origin: 'owner', fixed: true };\n}\n\nfunction toFlatItem(item: EffectiveCollectionItem): Record<string, unknown> {\n return { id: item.id, ...item.values };\n}\n\nfunction scalarValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, current: EffectivePropertyValue, diagnostics: SceneDiagnostic[]): void {\n for (const contribution of matching) {\n const problem = contribution.value === undefined ? 'a value is required' : validateValue(grant.descriptor, contribution.value);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTypeMismatch,\n `The saved value of '${grant.path}' set by '${instance}' is ignored: ${problem}. It is kept, and applies again when it fits.`,\n { instance, component: grant.component, path: grant.path }));\n continue;\n }\n\n current.value = contribution.value;\n current.source = ValueSource.Instance;\n current.contributedBy = instance;\n }\n}\n\nfunction collectionValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, items: EffectiveCollectionItem[], diagnostics: SceneDiagnostic[]): boolean {\n let contributed = false;\n\n for (const contribution of matching) {\n const context = { instance, component: grant.component, path: grant.path };\n if (contribution.items === undefined) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionTypeMismatch, `The saved value of '${grant.path}' set by '${instance}' is ignored: a collection takes items.`, context));\n continue;\n }\n\n if (contribution.items.length > 0 && !grant.operations.includes(CollectionOperation.Add)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionOperationNotPermitted,\n `'${instance}' has items in '${grant.path}', but adding items is not exposed. They are ignored and kept.`,\n context));\n continue;\n }\n\n for (const item of contribution.items) {\n const itemContext = { ...context, itemId: item.id };\n if (items.some(existing => existing.id === item.id)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.DuplicateCollectionItem, `The item id '${item.id}' in '${grant.path}' is already used.`, itemContext));\n continue;\n }\n\n const values: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(item.values)) {\n if (grant.editableFields !== undefined && !grant.editableFields.includes(field)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionOperationNotPermitted, `The field '${field}' of '${grant.path}' is not exposed for editing.`, itemContext));\n continue;\n }\n\n const problem = validateItemValues(grant.descriptor.item, { [field]: value }).find(candidate => candidate.field === field);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n problem.problem.startsWith('is not a field') ? DiagnosticCode.UnknownCollectionField : DiagnosticCode.ContributionTypeMismatch,\n `The field '${field}' of an item in '${grant.path}' is ignored: ${problem.problem}.`,\n itemContext));\n continue;\n }\n\n values[field] = value;\n }\n\n items.push({ id: item.id, values, origin: instance, fixed: false });\n contributed = true;\n }\n }\n\n return contributed;\n}\n\n/**\n * Resolves what every configurable component in a template chain is worth: the owner's own values, with each\n * instance's contributions applied in nesting order.\n *\n * This is the one merge. The editor shows its result and the runtime renders from it, so what an author sees is\n * what Play renders. Order is fixed: the owner's value first, then each level from the outermost inwards, so a\n * later level wins a scalar and appends to a collection after the earlier ones.\n *\n * Nothing in the persisted data is changed. A contribution that cannot apply - the exposure was withdrawn, the\n * property's type changed, the component is gone - is reported in `diagnostics` and left out of the result, and\n * stays in `instanceContributions`, so restoring the exposure brings its value back.\n *\n * @param templateChain The nesting, from {@link resolveTemplateChain} or built by hand.\n * @param instanceContributions What each instance has set.\n * @param catalog The descriptors saying what each component supports.\n */\nexport function resolveEffectiveConfiguration(\n templateChain: TemplateChain,\n instanceContributions: InstanceContribution[],\n catalog: DescriptorCatalog,\n): EffectiveConfiguration {\n const grants = computeExposureGrants(templateChain, catalog);\n const diagnostics: SceneDiagnostic[] = [...templateChain.diagnostics, ...grants.diagnostics];\n const handled = new Set<InstanceContribution>();\n const components = new Map<string, EffectiveComponentConfiguration>();\n\n for (const grant of grants.exposed) {\n const owner = templateChain.levels[grant.ownerLevel];\n const element = owner.elements.find(candidate => candidate.id === grant.component)!;\n\n let configuration = components.get(grant.component);\n if (!configuration) {\n configuration = { component: grant.component, owner: owner.owner, properties: cloneData(element.properties), values: [] };\n components.set(grant.component, configuration);\n }\n\n const stored = getValueAtPath(element.properties, grant.path);\n const base = stored === undefined ? cloneData(grant.descriptor.default) : cloneData(stored);\n const isCollection = grant.descriptor.valueType === PropertyValueType.Collection;\n const baseItems = isCollection && Array.isArray(base) ? base.map(toEffectiveItem) : [];\n const items = [...baseItems];\n\n const current: EffectivePropertyValue = {\n path: grant.path,\n value: base,\n source: stored === undefined ? ValueSource.Default : ValueSource.Local,\n inheritedValue: base,\n };\n let contributed = false;\n\n for (let index = grant.ownerLevel + 1; index < templateChain.levels.length; index++) {\n const instance = templateChain.levels[index].instance;\n if (!grants.byInstance.get(instance)?.has(grantKey(grant.component, grant.path))) continue;\n\n const effectiveGrant = grants.byInstance.get(instance)!.get(grantKey(grant.component, grant.path))!;\n const matching = instanceContributions.filter(contribution =>\n contribution.instance === instance && contribution.component === grant.component && contribution.path === grant.path);\n for (const contribution of matching) handled.add(contribution);\n\n if (isCollection) {\n if (collectionValue(effectiveGrant, matching, instance, items, diagnostics)) {\n contributed = true;\n current.contributedBy = instance;\n }\n } else {\n scalarValue(effectiveGrant, matching, instance, current, diagnostics);\n }\n }\n\n if (isCollection) {\n current.items = items;\n current.inheritedValue = baseItems.map(toFlatItem);\n current.value = items.map(toFlatItem);\n if (contributed) current.source = ValueSource.Instance;\n }\n\n if (current.value !== undefined) setValueAtPath(configuration.properties, grant.path, current.value);\n configuration.values.push(current);\n }\n\n const levelOf = new Map(templateChain.levels.map((chainLevel, index) => [chainLevel.instance, index]));\n for (const contribution of instanceContributions) {\n const contributorLevel = levelOf.get(contribution.instance);\n if (contributorLevel === undefined || handled.has(contribution)) continue;\n\n const context = { instance: contribution.instance, component: contribution.component, path: contribution.path };\n const owner = templateChain.levels.slice(0, contributorLevel).find(chainLevel => chainLevel.elements.some(element => element.id === contribution.component));\n if (!owner) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTargetMissing,\n `'${contribution.instance}' has saved values for '${contribution.component}', which is not in any layout or template above it. They are kept.`,\n context));\n } else if (!findComponentDescriptor(catalog, owner.elements.find(element => element.id === contribution.component)!.componentName)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.MissingComponentDescriptor,\n `'${contribution.instance}' has saved values for '${contribution.component}', but nothing describes that component any more. They are kept.`,\n context));\n } else {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionNotExposed,\n `'${contribution.instance}' has a saved value for '${contribution.path}' on '${contribution.component}', which is not exposed to it. It is ignored and kept.`,\n context));\n }\n }\n\n return { components: [...components.values()], diagnostics };\n}\n"],"names":["toEffectiveItem","item","index","id","values","length","origin","fixed","toFlatItem","scalarValue","grant","matching","instance","current","diagnostics","contribution","problem","value","undefined","validateValue","descriptor","push","errorDiagnostic","DiagnosticCode","ContributionTypeMismatch","path","component","source","ValueSource","Instance","contributedBy","collectionValue","items","contributed","context","operations","includes","CollectionOperation","Add","ContributionOperationNotPermitted","itemContext","itemId","some","existing","DuplicateCollectionItem","field","Object","entries","editableFields","validateItemValues","find","candidate","startsWith","UnknownCollectionField","resolveEffectiveConfiguration","templateChain","instanceContributions","catalog","grants","computeExposureGrants","handled","Set","components","Map","exposed","owner","levels","ownerLevel","element","elements","configuration","get","properties","cloneData","set","stored","getValueAtPath","base","default","isCollection","valueType","PropertyValueType","Collection","baseItems","Array","isArray","map","Default","Local","inheritedValue","byInstance","has","grantKey","effectiveGrant","filter","add","setValueAtPath","levelOf","chainLevel","contributorLevel","slice","ContributionTargetMissing","findComponentDescriptor","componentName","MissingComponentDescriptor","ContributionNotExposed"],"mappings":"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"}
1
+ {"version":3,"file":"resolveEffectiveConfiguration.js","sources":["../../../editing/resolveEffectiveConfiguration.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 {\n CollectionOperation, DiagnosticCode, EffectiveCollectionItem, EffectiveComponentConfiguration,\n EffectiveConfiguration, EffectivePropertyValue, InstanceContribution, PropertyValueType, SceneDiagnostic, ValueSource,\n} from '@cratis/scene.model';\nimport { DescriptorCatalog, findComponentDescriptor } from './DescriptorCatalog';\nimport { errorDiagnostic } from './diagnostics';\nimport { computeExposureGrants, ExposureGrant, grantKey } from './exposureGrants';\nimport { cloneData, getValueAtPath, setValueAtPath } from './pathAccess';\nimport { TemplateChain } from './TemplateChain';\nimport { validateItemValues, validateValue } from './validateValue';\n\n/**\n * Splits a flat collection item as it is stored on an element - `{ id, label, ... }` - into its id and fields.\n */\nfunction toEffectiveItem(item: unknown, index: number): EffectiveCollectionItem {\n const { id, ...values } = (item !== null && typeof item === 'object' ? item : {}) as Record<string, unknown>;\n return { id: typeof id === 'string' && id.length > 0 ? id : `owner-${index}`, values, origin: 'owner', fixed: true };\n}\n\nfunction toFlatItem(item: EffectiveCollectionItem): Record<string, unknown> {\n return { id: item.id, ...item.values };\n}\n\nfunction scalarValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, current: EffectivePropertyValue, diagnostics: SceneDiagnostic[]): void {\n for (const contribution of matching) {\n const problem = contribution.value === undefined ? 'a value is required' : validateValue(grant.descriptor, contribution.value);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTypeMismatch,\n `The saved value of '${grant.path}' set by '${instance}' is ignored: ${problem}. It is kept, and applies again when it fits.`,\n { instance, component: grant.component, path: grant.path }));\n continue;\n }\n\n current.value = contribution.value;\n current.source = ValueSource.Instance;\n current.contributedBy = instance;\n }\n}\n\nfunction collectionValue(grant: ExposureGrant, matching: InstanceContribution[], instance: string, items: EffectiveCollectionItem[], diagnostics: SceneDiagnostic[]): boolean {\n let contributed = false;\n\n for (const contribution of matching) {\n const context = { instance, component: grant.component, path: grant.path };\n if (contribution.items === undefined) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionTypeMismatch, `The saved value of '${grant.path}' set by '${instance}' is ignored: a collection takes items.`, context));\n continue;\n }\n\n if (contribution.items.length > 0 && !grant.operations.includes(CollectionOperation.Add)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionOperationNotPermitted,\n `'${instance}' has items in '${grant.path}', but adding items is not exposed. They are ignored and kept.`,\n context));\n continue;\n }\n\n for (const item of contribution.items) {\n const itemContext = { ...context, itemId: item.id };\n if (items.some(existing => existing.id === item.id)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.DuplicateCollectionItem, `The item id '${item.id}' in '${grant.path}' is already used.`, itemContext));\n continue;\n }\n\n const values: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(item.values)) {\n if (grant.editableFields !== undefined && !grant.editableFields.includes(field)) {\n diagnostics.push(errorDiagnostic(DiagnosticCode.ContributionOperationNotPermitted, `The field '${field}' of '${grant.path}' is not exposed for editing.`, itemContext));\n continue;\n }\n\n const problem = validateItemValues(grant.descriptor.item, { [field]: value }).find(candidate => candidate.field === field);\n if (problem) {\n diagnostics.push(errorDiagnostic(\n problem.problem.startsWith('is not a field') ? DiagnosticCode.UnknownCollectionField : DiagnosticCode.ContributionTypeMismatch,\n `The field '${field}' of an item in '${grant.path}' is ignored: ${problem.problem}.`,\n itemContext));\n continue;\n }\n\n values[field] = value;\n }\n\n items.push({ id: item.id, values, origin: instance, fixed: false });\n contributed = true;\n }\n }\n\n return contributed;\n}\n\n/**\n * Resolves what every configurable component in a template chain is worth: the owner's own values, with each\n * instance's contributions applied in nesting order.\n *\n * This is the one merge. The editor shows its result and the runtime renders from it, so what an author sees is\n * what Play renders. Order is fixed: the owner's value first, then each level from the outermost inwards, so a\n * later level wins a scalar and appends to a collection after the earlier ones.\n *\n * Nothing in the persisted data is changed. A contribution that cannot apply - the exposure was withdrawn, the\n * property's type changed, the component is gone - is reported in `diagnostics` and left out of the result, and\n * stays in `instanceContributions`, so restoring the exposure brings its value back.\n *\n * @param templateChain The nesting, from {@link resolveTemplateChain} or built by hand.\n * @param instanceContributions What each instance has set.\n * @param catalog The descriptors saying what each component supports.\n */\nexport function resolveEffectiveConfiguration(\n templateChain: TemplateChain,\n instanceContributions: InstanceContribution[],\n catalog: DescriptorCatalog,\n): EffectiveConfiguration {\n const grants = computeExposureGrants(templateChain, catalog);\n const diagnostics: SceneDiagnostic[] = [...templateChain.diagnostics, ...grants.diagnostics];\n const handled = new Set<InstanceContribution>();\n const components = new Map<string, EffectiveComponentConfiguration>();\n\n for (const grant of grants.exposed) {\n const owner = templateChain.levels[grant.ownerLevel];\n const element = owner.elements.find(candidate => candidate.id === grant.component)!;\n\n let configuration = components.get(grant.component);\n if (!configuration) {\n configuration = { component: grant.component, owner: owner.owner, properties: cloneData(element.properties), values: [] };\n components.set(grant.component, configuration);\n }\n\n const stored = getValueAtPath(element.properties, grant.path);\n const base = stored === undefined ? cloneData(grant.descriptor.default) : cloneData(stored);\n const isCollection = grant.descriptor.valueType === PropertyValueType.Collection;\n const baseItems = isCollection && Array.isArray(base) ? base.map(toEffectiveItem) : [];\n const items = [...baseItems];\n\n const current: EffectivePropertyValue = {\n path: grant.path,\n value: base,\n source: stored === undefined ? ValueSource.Default : ValueSource.Local,\n inheritedValue: base,\n };\n let contributed = false;\n\n for (let index = grant.ownerLevel + 1; index < templateChain.levels.length; index++) {\n const instance = templateChain.levels[index].instance;\n if (!grants.byInstance.get(instance)?.has(grantKey(grant.component, grant.path))) continue;\n\n const effectiveGrant = grants.byInstance.get(instance)!.get(grantKey(grant.component, grant.path))!;\n const matching = instanceContributions.filter(contribution =>\n contribution.instance === instance && contribution.component === grant.component && contribution.path === grant.path);\n for (const contribution of matching) handled.add(contribution);\n\n if (isCollection) {\n if (collectionValue(effectiveGrant, matching, instance, items, diagnostics)) {\n contributed = true;\n current.contributedBy = instance;\n }\n } else {\n scalarValue(effectiveGrant, matching, instance, current, diagnostics);\n }\n }\n\n const maximumItems = grant.descriptor.constraints?.maximumItems;\n if (isCollection && maximumItems !== undefined && items.length > maximumItems) {\n // Saved items that no longer fit - the owner lowered the limit after they were added - are left out of\n // the result in order and kept in the saved data, like any other saved value that no longer fits.\n const dropped = items.splice(maximumItems);\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTypeMismatch,\n `'${grant.path}' on '${grant.component}' allows at most ${maximumItems} items; ${dropped.map(item => `'${item.id}'`).join(', ')} ${dropped.length === 1 ? 'is' : 'are'} ignored and kept.`,\n { instance: current.contributedBy ?? owner.instance, component: grant.component, path: grant.path }));\n }\n\n if (isCollection) {\n current.items = items;\n current.inheritedValue = baseItems.map(toFlatItem);\n current.value = items.map(toFlatItem);\n if (contributed) current.source = ValueSource.Instance;\n }\n\n if (current.value !== undefined) setValueAtPath(configuration.properties, grant.path, current.value);\n configuration.values.push(current);\n }\n\n const levelOf = new Map(templateChain.levels.map((chainLevel, index) => [chainLevel.instance, index]));\n for (const contribution of instanceContributions) {\n const contributorLevel = levelOf.get(contribution.instance);\n if (contributorLevel === undefined || handled.has(contribution)) continue;\n\n const context = { instance: contribution.instance, component: contribution.component, path: contribution.path };\n const owner = templateChain.levels.slice(0, contributorLevel).find(chainLevel => chainLevel.elements.some(element => element.id === contribution.component));\n if (!owner) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionTargetMissing,\n `'${contribution.instance}' has saved values for '${contribution.component}', which is not in any layout or template above it. They are kept.`,\n context));\n } else if (!findComponentDescriptor(catalog, owner.elements.find(element => element.id === contribution.component)!.componentName)) {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.MissingComponentDescriptor,\n `'${contribution.instance}' has saved values for '${contribution.component}', but nothing describes that component any more. They are kept.`,\n context));\n } else {\n diagnostics.push(errorDiagnostic(\n DiagnosticCode.ContributionNotExposed,\n `'${contribution.instance}' has a saved value for '${contribution.path}' on '${contribution.component}', which is not exposed to it. It is ignored and kept.`,\n context));\n }\n }\n\n return { components: [...components.values()], diagnostics };\n}\n"],"names":["toEffectiveItem","item","index","id","values","length","origin","fixed","toFlatItem","scalarValue","grant","matching","instance","current","diagnostics","contribution","problem","value","undefined","validateValue","descriptor","push","errorDiagnostic","DiagnosticCode","ContributionTypeMismatch","path","component","source","ValueSource","Instance","contributedBy","collectionValue","items","contributed","context","operations","includes","CollectionOperation","Add","ContributionOperationNotPermitted","itemContext","itemId","some","existing","DuplicateCollectionItem","field","Object","entries","editableFields","validateItemValues","find","candidate","startsWith","UnknownCollectionField","resolveEffectiveConfiguration","templateChain","instanceContributions","catalog","grants","computeExposureGrants","handled","Set","components","Map","exposed","owner","levels","ownerLevel","element","elements","configuration","get","properties","cloneData","set","stored","getValueAtPath","base","default","isCollection","valueType","PropertyValueType","Collection","baseItems","Array","isArray","map","Default","Local","inheritedValue","byInstance","has","grantKey","effectiveGrant","filter","add","maximumItems","constraints","dropped","splice","join","setValueAtPath","levelOf","chainLevel","contributorLevel","slice","ContributionTargetMissing","findComponentDescriptor","componentName","MissingComponentDescriptor","ContributionNotExposed"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validateValue.d.ts","sourceRoot":"","sources":["../../../editing/validateValue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAqB,MAAM,qBAAqB,CAAC;AAiBtG,wBAAgB,aAAa,CAAC,UAAU,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAqDhG;AAmDD,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,CAsB5I"}
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,CA4DhG;AAgED,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,CAsB5I"}
@@ -1,4 +1,4 @@
1
- import { PropertyValueType } from '@cratis/scene.model';
1
+ import { BindingSourceKind, PropertyValueType } from '@cratis/scene.model';
2
2
 
3
3
  // Copyright (c) Cratis. All rights reserved.
4
4
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -19,6 +19,10 @@ function isNonEmptyString(value) {
19
19
  if (value === undefined || value === null) {
20
20
  return constraints.required ? 'a value is required' : undefined;
21
21
  }
22
+ const binding = bindingKindOf(value);
23
+ if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {
24
+ return descriptor.acceptedBindingKinds.includes(binding.kind) ? undefined : `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;
25
+ }
22
26
  switch(descriptor.valueType){
23
27
  case PropertyValueType.String:
24
28
  {
@@ -61,7 +65,19 @@ function isNonEmptyString(value) {
61
65
  /**
62
66
  * The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;
63
67
  * the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.
64
- */ const maximumJsonDepth = 64;
68
+ */ const bindingKinds = new Set(Object.values(BindingSourceKind));
69
+ /**
70
+ * The source kind of a value that is a typed binding expression - an object with a known `kind` and a
71
+ * string `path` - rather than a value of the property's own type. Only consulted for properties that declare
72
+ * `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a
73
+ * table's `selectedItem` instead of listing its items.
74
+ */ function bindingKindOf(value) {
75
+ if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;
76
+ return {
77
+ kind: value.kind
78
+ };
79
+ }
80
+ const maximumJsonDepth = 64;
65
81
  /**
66
82
  * Whether a value is JSON: `null`, a string, a boolean, a finite number, or an array or plain object of those.
67
83
  * The value is only inspected, never serialized, so what an editor stores is exactly what was passed in.
@@ -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 { 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 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 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","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","maximumJsonDepth","parents","Set","has","size","prototype","Object","getPrototypeOf","add","values","from","_","index","valid","every","candidate","delete","minimumItems","maximumItems","identities","item","id","_identity","problem","validateItemValues","at","field","itemDescriptor","fields","properties","problems","fieldValue","entries","fieldDescriptor","find","path","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.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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"}
@@ -4,6 +4,7 @@ export * from './BindingScope';
4
4
  export * from './BindingDiagnostic';
5
5
  export * from './resolveBindingExpression';
6
6
  export * from './nestBindingScope';
7
+ export * from './resolveArgumentSource';
7
8
  export * from './removeComponentOutputs';
8
9
  export * from './QueryBindingState';
9
10
  export * from './QueryBindingTicket';