@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.
- package/dist/cjs/editing/resolveEffectiveConfiguration.js +11 -0
- package/dist/cjs/editing/resolveEffectiveConfiguration.js.map +1 -1
- package/dist/cjs/editing/validateValue.js +17 -1
- package/dist/cjs/editing/validateValue.js.map +1 -1
- package/dist/cjs/index.js +3 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/resolveArgumentSource.js +36 -0
- package/dist/cjs/resolveArgumentSource.js.map +1 -0
- package/dist/esm/editing/resolveEffectiveConfiguration.d.ts.map +1 -1
- package/dist/esm/editing/resolveEffectiveConfiguration.js +11 -0
- package/dist/esm/editing/resolveEffectiveConfiguration.js.map +1 -1
- package/dist/esm/editing/validateValue.d.ts.map +1 -1
- package/dist/esm/editing/validateValue.js +18 -2
- package/dist/esm/editing/validateValue.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resolveArgumentSource.d.ts +4 -0
- package/dist/esm/resolveArgumentSource.d.ts.map +1 -0
- package/dist/esm/resolveArgumentSource.js +33 -0
- package/dist/esm/resolveArgumentSource.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/editing/resolveEffectiveConfiguration.ts +11 -0
- package/editing/validateValue.ts +21 -1
- package/index.ts +1 -0
- package/package.json +3 -3
- package/resolveArgumentSource.ts +33 -0
|
@@ -162,6 +162,17 @@ export function resolveEffectiveConfiguration(
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
const maximumItems = grant.descriptor.constraints?.maximumItems;
|
|
166
|
+
if (isCollection && maximumItems !== undefined && items.length > maximumItems) {
|
|
167
|
+
// Saved items that no longer fit - the owner lowered the limit after they were added - are left out of
|
|
168
|
+
// the result in order and kept in the saved data, like any other saved value that no longer fits.
|
|
169
|
+
const dropped = items.splice(maximumItems);
|
|
170
|
+
diagnostics.push(errorDiagnostic(
|
|
171
|
+
DiagnosticCode.ContributionTypeMismatch,
|
|
172
|
+
`'${grant.path}' on '${grant.component}' allows at most ${maximumItems} items; ${dropped.map(item => `'${item.id}'`).join(', ')} ${dropped.length === 1 ? 'is' : 'are'} ignored and kept.`,
|
|
173
|
+
{ instance: current.contributedBy ?? owner.instance, component: grant.component, path: grant.path }));
|
|
174
|
+
}
|
|
175
|
+
|
|
165
176
|
if (isCollection) {
|
|
166
177
|
current.items = items;
|
|
167
178
|
current.inheritedValue = baseItems.map(toFlatItem);
|
package/editing/validateValue.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
|
-
import { CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';
|
|
4
|
+
import { BindingSourceKind, CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';
|
|
5
5
|
|
|
6
6
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
7
7
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -24,6 +24,13 @@ export function validateValue(descriptor: PropertyDescriptor, value: unknown): s
|
|
|
24
24
|
return constraints.required ? 'a value is required' : undefined;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const binding = bindingKindOf(value);
|
|
28
|
+
if (binding !== undefined && descriptor.acceptedBindingKinds !== undefined) {
|
|
29
|
+
return descriptor.acceptedBindingKinds.includes(binding.kind)
|
|
30
|
+
? undefined
|
|
31
|
+
: `a ${binding.kind} binding is not accepted here; use ${descriptor.acceptedBindingKinds.join(' or ')}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
switch (descriptor.valueType) {
|
|
28
35
|
case PropertyValueType.String: {
|
|
29
36
|
if (typeof value !== 'string') return 'expected a string';
|
|
@@ -77,6 +84,19 @@ export function validateValue(descriptor: PropertyDescriptor, value: unknown): s
|
|
|
77
84
|
* The deepest nesting a JSON value may have. Authored configuration (chart datasets, option lists) is shallow;
|
|
78
85
|
* the limit turns a runaway or hostile structure into a validation message instead of a stack overflow.
|
|
79
86
|
*/
|
|
87
|
+
const bindingKinds = new Set<string>(Object.values(BindingSourceKind));
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The source kind of a value that is a typed binding expression - an object with a known `kind` and a
|
|
91
|
+
* string `path` - rather than a value of the property's own type. Only consulted for properties that declare
|
|
92
|
+
* `acceptedBindingKinds`, so a collection property such as a command form's `inputs` can be bound to a
|
|
93
|
+
* table's `selectedItem` instead of listing its items.
|
|
94
|
+
*/
|
|
95
|
+
function bindingKindOf(value: unknown): { kind: BindingSourceKind } | undefined {
|
|
96
|
+
if (!isRecord(value) || typeof value.kind !== 'string' || !bindingKinds.has(value.kind) || typeof value.path !== 'string') return undefined;
|
|
97
|
+
return { kind: value.kind as BindingSourceKind };
|
|
98
|
+
}
|
|
99
|
+
|
|
80
100
|
const maximumJsonDepth = 64;
|
|
81
101
|
|
|
82
102
|
/**
|
package/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './BindingScope';
|
|
|
7
7
|
export * from './BindingDiagnostic';
|
|
8
8
|
export * from './resolveBindingExpression';
|
|
9
9
|
export * from './nestBindingScope';
|
|
10
|
+
export * from './resolveArgumentSource';
|
|
10
11
|
export * from './removeComponentOutputs';
|
|
11
12
|
export * from './QueryBindingState';
|
|
12
13
|
export * from './QueryBindingTicket';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cratis/scene.engine",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.0",
|
|
4
4
|
"description": "The Scene runtime: walks a Scene element tree and drives whichever renderer is plugged in. Does not know React, or any other rendering platform, exists.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cratis",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"up": "yarn g:up"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@cratis/scene.model": "4.
|
|
51
|
+
"@cratis/scene.model": "4.17.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@cratis/scene.model": "4.
|
|
54
|
+
"@cratis/scene.model": "4.17.0"
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { BindingSourceKind } from '@cratis/scene.model';
|
|
5
|
+
import { BindingScope } from './BindingScope';
|
|
6
|
+
import { resolveBindingExpression } from './resolveBindingExpression';
|
|
7
|
+
|
|
8
|
+
/** The prefix of an argument source that reads another element's output. */
|
|
9
|
+
export const componentArgumentSourcePrefix = 'component.';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolves where a command argument comes from, as an action's argument mapping writes it.
|
|
13
|
+
*
|
|
14
|
+
* `component.<id>.<output>` reads an output another element publishes - an input's `value`, a table's
|
|
15
|
+
* `selectedItem.id` - from the same output scope a `componentProperty` binding reads. Element ids may contain
|
|
16
|
+
* dots, so the longest id with outputs in scope wins: `component.order.lines.value` reads `value` of
|
|
17
|
+
* `order.lines` when that element exists. Any other source is a path in the data context. An empty source,
|
|
18
|
+
* or an element with no outputs in scope, resolves as absent.
|
|
19
|
+
*
|
|
20
|
+
* The C# engine (`ArgumentSources.Resolve`) behaves identically; both run `argument-source-fixtures.json`.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveArgumentSource(source: string, scope: BindingScope): unknown {
|
|
23
|
+
if (!source) return undefined;
|
|
24
|
+
if (!source.startsWith(componentArgumentSourcePrefix)) return resolveBindingExpression({ path: source }, scope);
|
|
25
|
+
|
|
26
|
+
const reference = source.substring(componentArgumentSourcePrefix.length);
|
|
27
|
+
const componentId = Object.keys(scope.componentOutputs ?? {})
|
|
28
|
+
.filter(id => reference === id || reference.startsWith(`${id}.`))
|
|
29
|
+
.sort((left, right) => right.length - left.length)[0];
|
|
30
|
+
if (componentId === undefined) return undefined;
|
|
31
|
+
|
|
32
|
+
return resolveBindingExpression({ kind: BindingSourceKind.ComponentProperty, componentId, path: reference.substring(componentId.length + 1) }, scope);
|
|
33
|
+
}
|