@cratis/scene.engine 4.2.1 → 4.4.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/DescriptorCatalog.js +42 -0
- package/dist/cjs/editing/DescriptorCatalog.js.map +1 -0
- package/dist/cjs/editing/EditSession.js +44 -0
- package/dist/cjs/editing/EditSession.js.map +1 -0
- package/dist/cjs/editing/applyEdit.js +83 -0
- package/dist/cjs/editing/applyEdit.js.map +1 -0
- package/dist/cjs/editing/applyEffectiveConfiguration.js +62 -0
- package/dist/cjs/editing/applyEffectiveConfiguration.js.map +1 -0
- package/dist/cjs/editing/collectComponents.js +34 -0
- package/dist/cjs/editing/collectComponents.js.map +1 -0
- package/dist/cjs/editing/collectIconUsages.js +86 -0
- package/dist/cjs/editing/collectIconUsages.js.map +1 -0
- package/dist/cjs/editing/describeNode.js +63 -0
- package/dist/cjs/editing/describeNode.js.map +1 -0
- package/dist/cjs/editing/diagnoseIcons.js +67 -0
- package/dist/cjs/editing/diagnoseIcons.js.map +1 -0
- package/dist/cjs/editing/diagnostics.js +36 -0
- package/dist/cjs/editing/diagnostics.js.map +1 -0
- package/dist/cjs/editing/documentPaths.js +45 -0
- package/dist/cjs/editing/documentPaths.js.map +1 -0
- package/dist/cjs/editing/exposureEdits.js +106 -0
- package/dist/cjs/editing/exposureEdits.js.map +1 -0
- package/dist/cjs/editing/exposureGrants.js +115 -0
- package/dist/cjs/editing/exposureGrants.js.map +1 -0
- package/dist/cjs/editing/iconDiagnostics.js +103 -0
- package/dist/cjs/editing/iconDiagnostics.js.map +1 -0
- package/dist/cjs/editing/indexDocument.js +400 -0
- package/dist/cjs/editing/indexDocument.js.map +1 -0
- package/dist/cjs/editing/inspect.js +154 -0
- package/dist/cjs/editing/inspect.js.map +1 -0
- package/dist/cjs/editing/instanceEdits.js +267 -0
- package/dist/cjs/editing/instanceEdits.js.map +1 -0
- package/dist/cjs/editing/layoutTypeDescriptors.js +425 -0
- package/dist/cjs/editing/layoutTypeDescriptors.js.map +1 -0
- package/dist/cjs/editing/layoutTypeEdits.js +141 -0
- package/dist/cjs/editing/layoutTypeEdits.js.map +1 -0
- package/dist/cjs/editing/nodeIds.js +115 -0
- package/dist/cjs/editing/nodeIds.js.map +1 -0
- package/dist/cjs/editing/pathAccess.js +53 -0
- package/dist/cjs/editing/pathAccess.js.map +1 -0
- package/dist/cjs/editing/propertyEdits.js +125 -0
- package/dist/cjs/editing/propertyEdits.js.map +1 -0
- package/dist/cjs/editing/resolveEffectiveConfiguration.js +200 -0
- package/dist/cjs/editing/resolveEffectiveConfiguration.js.map +1 -0
- package/dist/cjs/editing/resolveTemplateChain.js +100 -0
- package/dist/cjs/editing/resolveTemplateChain.js.map +1 -0
- package/dist/cjs/editing/structureEdits.js +231 -0
- package/dist/cjs/editing/structureEdits.js.map +1 -0
- package/dist/cjs/editing/validateBinding.js +111 -0
- package/dist/cjs/editing/validateBinding.js.map +1 -0
- package/dist/cjs/editing/validateValue.js +114 -0
- package/dist/cjs/editing/validateValue.js.map +1 -0
- package/dist/cjs/icons/EffectiveIconCatalog.js +212 -0
- package/dist/cjs/icons/EffectiveIconCatalog.js.map +1 -0
- package/dist/cjs/icons/EffectiveIconEntry.js +22 -0
- package/dist/cjs/icons/EffectiveIconEntry.js.map +1 -0
- package/dist/cjs/icons/analyzeIconImpact.js +48 -0
- package/dist/cjs/icons/analyzeIconImpact.js.map +1 -0
- package/dist/cjs/icons/matchesIconQuery.js +22 -0
- package/dist/cjs/icons/matchesIconQuery.js.map +1 -0
- package/dist/cjs/icons/resolveIconLibraries.js +45 -0
- package/dist/cjs/icons/resolveIconLibraries.js.map +1 -0
- package/dist/cjs/index.js +67 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/editing/DescriptorCatalog.d.ts +9 -0
- package/dist/esm/editing/DescriptorCatalog.d.ts.map +1 -0
- package/dist/esm/editing/DescriptorCatalog.js +38 -0
- package/dist/esm/editing/DescriptorCatalog.js.map +1 -0
- package/dist/esm/editing/DocumentIndex.d.ts +31 -0
- package/dist/esm/editing/DocumentIndex.d.ts.map +1 -0
- package/dist/esm/editing/DocumentIndex.js +2 -0
- package/dist/esm/editing/DocumentIndex.js.map +1 -0
- package/dist/esm/editing/EditOutcome.d.ts +7 -0
- package/dist/esm/editing/EditOutcome.d.ts.map +1 -0
- package/dist/esm/editing/EditOutcome.js +2 -0
- package/dist/esm/editing/EditOutcome.js.map +1 -0
- package/dist/esm/editing/EditSession.d.ts +20 -0
- package/dist/esm/editing/EditSession.d.ts.map +1 -0
- package/dist/esm/editing/EditSession.js +42 -0
- package/dist/esm/editing/EditSession.js.map +1 -0
- package/dist/esm/editing/EditingContext.d.ts +10 -0
- package/dist/esm/editing/EditingContext.d.ts.map +1 -0
- package/dist/esm/editing/EditingContext.js +2 -0
- package/dist/esm/editing/EditingContext.js.map +1 -0
- package/dist/esm/editing/TemplateChain.d.ts +13 -0
- package/dist/esm/editing/TemplateChain.d.ts.map +1 -0
- package/dist/esm/editing/TemplateChain.js +2 -0
- package/dist/esm/editing/TemplateChain.js.map +1 -0
- package/dist/esm/editing/applyEdit.d.ts +5 -0
- package/dist/esm/editing/applyEdit.d.ts.map +1 -0
- package/dist/esm/editing/applyEdit.js +81 -0
- package/dist/esm/editing/applyEdit.js.map +1 -0
- package/dist/esm/editing/applyEffectiveConfiguration.d.ts +3 -0
- package/dist/esm/editing/applyEffectiveConfiguration.d.ts.map +1 -0
- package/dist/esm/editing/applyEffectiveConfiguration.js +60 -0
- package/dist/esm/editing/applyEffectiveConfiguration.js.map +1 -0
- package/dist/esm/editing/collectComponents.d.ts +3 -0
- package/dist/esm/editing/collectComponents.d.ts.map +1 -0
- package/dist/esm/editing/collectComponents.js +32 -0
- package/dist/esm/editing/collectComponents.js.map +1 -0
- package/dist/esm/editing/collectIconUsages.d.ts +5 -0
- package/dist/esm/editing/collectIconUsages.d.ts.map +1 -0
- package/dist/esm/editing/collectIconUsages.js +84 -0
- package/dist/esm/editing/collectIconUsages.js.map +1 -0
- package/dist/esm/editing/describeNode.d.ts +11 -0
- package/dist/esm/editing/describeNode.d.ts.map +1 -0
- package/dist/esm/editing/describeNode.js +60 -0
- package/dist/esm/editing/describeNode.js.map +1 -0
- package/dist/esm/editing/diagnoseIcons.d.ts +4 -0
- package/dist/esm/editing/diagnoseIcons.d.ts.map +1 -0
- package/dist/esm/editing/diagnoseIcons.js +65 -0
- package/dist/esm/editing/diagnoseIcons.js.map +1 -0
- package/dist/esm/editing/diagnostics.d.ts +6 -0
- package/dist/esm/editing/diagnostics.d.ts.map +1 -0
- package/dist/esm/editing/diagnostics.js +32 -0
- package/dist/esm/editing/diagnostics.js.map +1 -0
- package/dist/esm/editing/documentPaths.d.ts +8 -0
- package/dist/esm/editing/documentPaths.d.ts.map +1 -0
- package/dist/esm/editing/documentPaths.js +41 -0
- package/dist/esm/editing/documentPaths.js.map +1 -0
- package/dist/esm/editing/exposureEdits.d.ts +5 -0
- package/dist/esm/editing/exposureEdits.d.ts.map +1 -0
- package/dist/esm/editing/exposureEdits.js +103 -0
- package/dist/esm/editing/exposureEdits.js.map +1 -0
- package/dist/esm/editing/exposureGrants.d.ts +21 -0
- package/dist/esm/editing/exposureGrants.d.ts.map +1 -0
- package/dist/esm/editing/exposureGrants.js +112 -0
- package/dist/esm/editing/exposureGrants.js.map +1 -0
- package/dist/esm/editing/given/a_layout_document.d.ts +14 -0
- package/dist/esm/editing/given/a_layout_document.d.ts.map +1 -0
- package/dist/esm/editing/given/a_layout_document.js +67 -0
- package/dist/esm/editing/given/a_layout_document.js.map +1 -0
- package/dist/esm/editing/given/a_scene_document.d.ts +20 -0
- package/dist/esm/editing/given/a_scene_document.d.ts.map +1 -0
- package/dist/esm/editing/given/a_scene_document.js +110 -0
- package/dist/esm/editing/given/a_scene_document.js.map +1 -0
- package/dist/esm/editing/iconDiagnostics.d.ts +11 -0
- package/dist/esm/editing/iconDiagnostics.d.ts.map +1 -0
- package/dist/esm/editing/iconDiagnostics.js +99 -0
- package/dist/esm/editing/iconDiagnostics.js.map +1 -0
- package/dist/esm/editing/index.d.ts +22 -0
- package/dist/esm/editing/index.d.ts.map +1 -0
- package/dist/esm/editing/index.js +22 -0
- package/dist/esm/editing/index.js.map +1 -0
- package/dist/esm/editing/indexDocument.d.ts +6 -0
- package/dist/esm/editing/indexDocument.d.ts.map +1 -0
- package/dist/esm/editing/indexDocument.js +396 -0
- package/dist/esm/editing/indexDocument.js.map +1 -0
- package/dist/esm/editing/inspect.d.ts +8 -0
- package/dist/esm/editing/inspect.d.ts.map +1 -0
- package/dist/esm/editing/inspect.js +151 -0
- package/dist/esm/editing/inspect.js.map +1 -0
- package/dist/esm/editing/instanceEdits.d.ts +9 -0
- package/dist/esm/editing/instanceEdits.d.ts.map +1 -0
- package/dist/esm/editing/instanceEdits.js +260 -0
- package/dist/esm/editing/instanceEdits.js.map +1 -0
- package/dist/esm/editing/layoutTypeDescriptors.d.ts +5 -0
- package/dist/esm/editing/layoutTypeDescriptors.d.ts.map +1 -0
- package/dist/esm/editing/layoutTypeDescriptors.js +421 -0
- package/dist/esm/editing/layoutTypeDescriptors.js.map +1 -0
- package/dist/esm/editing/layoutTypeEdits.d.ts +4 -0
- package/dist/esm/editing/layoutTypeEdits.d.ts.map +1 -0
- package/dist/esm/editing/layoutTypeEdits.js +139 -0
- package/dist/esm/editing/layoutTypeEdits.js.map +1 -0
- package/dist/esm/editing/nodeIds.d.ts +14 -0
- package/dist/esm/editing/nodeIds.d.ts.map +1 -0
- package/dist/esm/editing/nodeIds.js +102 -0
- package/dist/esm/editing/nodeIds.js.map +1 -0
- package/dist/esm/editing/pathAccess.d.ts +7 -0
- package/dist/esm/editing/pathAccess.d.ts.map +1 -0
- package/dist/esm/editing/pathAccess.js +48 -0
- package/dist/esm/editing/pathAccess.js.map +1 -0
- package/dist/esm/editing/propertyEdits.d.ts +15 -0
- package/dist/esm/editing/propertyEdits.d.ts.map +1 -0
- package/dist/esm/editing/propertyEdits.js +120 -0
- package/dist/esm/editing/propertyEdits.js.map +1 -0
- package/dist/esm/editing/resolveEffectiveConfiguration.d.ts +5 -0
- package/dist/esm/editing/resolveEffectiveConfiguration.d.ts.map +1 -0
- package/dist/esm/editing/resolveEffectiveConfiguration.js +198 -0
- package/dist/esm/editing/resolveEffectiveConfiguration.js.map +1 -0
- package/dist/esm/editing/resolveTemplateChain.d.ts +4 -0
- package/dist/esm/editing/resolveTemplateChain.d.ts.map +1 -0
- package/dist/esm/editing/resolveTemplateChain.js +98 -0
- package/dist/esm/editing/resolveTemplateChain.js.map +1 -0
- package/dist/esm/editing/structureEdits.d.ts +6 -0
- package/dist/esm/editing/structureEdits.d.ts.map +1 -0
- package/dist/esm/editing/structureEdits.js +227 -0
- package/dist/esm/editing/structureEdits.js.map +1 -0
- package/dist/esm/editing/validateBinding.d.ts +7 -0
- package/dist/esm/editing/validateBinding.d.ts.map +1 -0
- package/dist/esm/editing/validateBinding.js +108 -0
- package/dist/esm/editing/validateBinding.js.map +1 -0
- package/dist/esm/editing/validateValue.d.ts +8 -0
- package/dist/esm/editing/validateValue.d.ts.map +1 -0
- package/dist/esm/editing/validateValue.js +111 -0
- package/dist/esm/editing/validateValue.js.map +1 -0
- package/dist/esm/icons/EffectiveIconCatalog.d.ts +25 -0
- package/dist/esm/icons/EffectiveIconCatalog.d.ts.map +1 -0
- package/dist/esm/icons/EffectiveIconCatalog.js +210 -0
- package/dist/esm/icons/EffectiveIconCatalog.js.map +1 -0
- package/dist/esm/icons/EffectiveIconEntry.d.ts +9 -0
- package/dist/esm/icons/EffectiveIconEntry.d.ts.map +1 -0
- package/dist/esm/icons/EffectiveIconEntry.js +20 -0
- package/dist/esm/icons/EffectiveIconEntry.js.map +1 -0
- package/dist/esm/icons/IconCatalogSource.d.ts +6 -0
- package/dist/esm/icons/IconCatalogSource.d.ts.map +1 -0
- package/dist/esm/icons/IconCatalogSource.js +2 -0
- package/dist/esm/icons/IconCatalogSource.js.map +1 -0
- package/dist/esm/icons/IconDiagnostic.d.ts +9 -0
- package/dist/esm/icons/IconDiagnostic.d.ts.map +1 -0
- package/dist/esm/icons/IconDiagnostic.js +2 -0
- package/dist/esm/icons/IconDiagnostic.js.map +1 -0
- package/dist/esm/icons/IconImpactReport.d.ts +18 -0
- package/dist/esm/icons/IconImpactReport.d.ts.map +1 -0
- package/dist/esm/icons/IconImpactReport.js +2 -0
- package/dist/esm/icons/IconImpactReport.js.map +1 -0
- package/dist/esm/icons/IconLibraryResolution.d.ts +7 -0
- package/dist/esm/icons/IconLibraryResolution.d.ts.map +1 -0
- package/dist/esm/icons/IconLibraryResolution.js +2 -0
- package/dist/esm/icons/IconLibraryResolution.js.map +1 -0
- package/dist/esm/icons/IconQuery.d.ts +7 -0
- package/dist/esm/icons/IconQuery.d.ts.map +1 -0
- package/dist/esm/icons/IconQuery.js +2 -0
- package/dist/esm/icons/IconQuery.js.map +1 -0
- package/dist/esm/icons/IconResolution.d.ts +14 -0
- package/dist/esm/icons/IconResolution.d.ts.map +1 -0
- package/dist/esm/icons/IconResolution.js +2 -0
- package/dist/esm/icons/IconResolution.js.map +1 -0
- package/dist/esm/icons/IconSearchResult.d.ts +7 -0
- package/dist/esm/icons/IconSearchResult.d.ts.map +1 -0
- package/dist/esm/icons/IconSearchResult.js +2 -0
- package/dist/esm/icons/IconSearchResult.js.map +1 -0
- package/dist/esm/icons/IconUsage.d.ts +6 -0
- package/dist/esm/icons/IconUsage.d.ts.map +1 -0
- package/dist/esm/icons/IconUsage.js +2 -0
- package/dist/esm/icons/IconUsage.js.map +1 -0
- package/dist/esm/icons/ResolvedIconLibrary.d.ts +8 -0
- package/dist/esm/icons/ResolvedIconLibrary.d.ts.map +1 -0
- package/dist/esm/icons/ResolvedIconLibrary.js +2 -0
- package/dist/esm/icons/ResolvedIconLibrary.js.map +1 -0
- package/dist/esm/icons/analyzeIconImpact.d.ts +5 -0
- package/dist/esm/icons/analyzeIconImpact.d.ts.map +1 -0
- package/dist/esm/icons/analyzeIconImpact.js +46 -0
- package/dist/esm/icons/analyzeIconImpact.js.map +1 -0
- package/dist/esm/icons/index.d.ts +14 -0
- package/dist/esm/icons/index.d.ts.map +1 -0
- package/dist/esm/icons/index.js +14 -0
- package/dist/esm/icons/index.js.map +1 -0
- package/dist/esm/icons/matchesIconQuery.d.ts +4 -0
- package/dist/esm/icons/matchesIconQuery.d.ts.map +1 -0
- package/dist/esm/icons/matchesIconQuery.js +20 -0
- package/dist/esm/icons/matchesIconQuery.js.map +1 -0
- package/dist/esm/icons/resolveIconLibraries.d.ts +4 -0
- package/dist/esm/icons/resolveIconLibraries.d.ts.map +1 -0
- package/dist/esm/icons/resolveIconLibraries.js +43 -0
- package/dist/esm/icons/resolveIconLibraries.js.map +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/editing/DescriptorCatalog.ts +51 -0
- package/editing/DocumentIndex.ts +73 -0
- package/editing/EditOutcome.ts +21 -0
- package/editing/EditSession.ts +50 -0
- package/editing/EditingContext.ts +34 -0
- package/editing/TemplateChain.ts +36 -0
- package/editing/applyEdit.ts +69 -0
- package/editing/applyEffectiveConfiguration.ts +53 -0
- package/editing/collectComponents.ts +36 -0
- package/editing/collectIconUsages.ts +78 -0
- package/editing/describeNode.ts +61 -0
- package/editing/diagnoseIcons.ts +60 -0
- package/editing/diagnostics.ts +30 -0
- package/editing/documentPaths.ts +40 -0
- package/editing/exposureEdits.ts +119 -0
- package/editing/exposureGrants.ts +159 -0
- package/editing/given/a_layout_document.ts +88 -0
- package/editing/given/a_scene_document.ts +135 -0
- package/editing/iconDiagnostics.ts +90 -0
- package/editing/index.ts +24 -0
- package/editing/indexDocument.ts +237 -0
- package/editing/inspect.ts +165 -0
- package/editing/instanceEdits.ts +251 -0
- package/editing/layoutTypeDescriptors.ts +191 -0
- package/editing/layoutTypeEdits.ts +135 -0
- package/editing/nodeIds.ts +111 -0
- package/editing/pathAccess.ts +81 -0
- package/editing/propertyEdits.ts +127 -0
- package/editing/resolveEffectiveConfiguration.ts +202 -0
- package/editing/resolveTemplateChain.ts +109 -0
- package/editing/structureEdits.ts +234 -0
- package/editing/validateBinding.ts +103 -0
- package/editing/validateValue.ts +130 -0
- package/icons/EffectiveIconCatalog.ts +199 -0
- package/icons/EffectiveIconEntry.ts +36 -0
- package/icons/IconCatalogSource.ts +23 -0
- package/icons/IconDiagnostic.ts +45 -0
- package/icons/IconImpactReport.ts +63 -0
- package/icons/IconLibraryResolution.ts +22 -0
- package/icons/IconQuery.ts +27 -0
- package/icons/IconResolution.ts +25 -0
- package/icons/IconSearchResult.ts +21 -0
- package/icons/IconUsage.ts +21 -0
- package/icons/ResolvedIconLibrary.ts +32 -0
- package/icons/analyzeIconImpact.ts +41 -0
- package/icons/index.ts +16 -0
- package/icons/matchesIconQuery.ts +19 -0
- package/icons/resolveIconLibraries.ts +47 -0
- package/index.ts +2 -0
- package/package.json +3 -3
|
@@ -0,0 +1,130 @@
|
|
|
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 { CollectionItemDescriptor, PropertyDescriptor, PropertyValueType } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
7
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isNonEmptyString(value: unknown): value is string {
|
|
11
|
+
return typeof value === 'string' && value.length > 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks a value against a property descriptor.
|
|
16
|
+
*
|
|
17
|
+
* @param descriptor The property the value is for.
|
|
18
|
+
* @param value The value to check. `undefined` means "not set", which is fine unless the property is required.
|
|
19
|
+
* @returns The reason the value is not acceptable, or `undefined` when it is.
|
|
20
|
+
*/
|
|
21
|
+
export function validateValue(descriptor: PropertyDescriptor, value: unknown): string | undefined {
|
|
22
|
+
const constraints = descriptor.constraints ?? {};
|
|
23
|
+
if (value === undefined || value === null) {
|
|
24
|
+
return constraints.required ? 'a value is required' : undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
switch (descriptor.valueType) {
|
|
28
|
+
case PropertyValueType.String: {
|
|
29
|
+
if (typeof value !== 'string') return 'expected a string';
|
|
30
|
+
if (constraints.minimumLength !== undefined && value.length < constraints.minimumLength) return `must be at least ${constraints.minimumLength} characters`;
|
|
31
|
+
if (constraints.maximumLength !== undefined && value.length > constraints.maximumLength) return `must be at most ${constraints.maximumLength} characters`;
|
|
32
|
+
if (constraints.pattern !== undefined && !new RegExp(`^(?:${constraints.pattern})$`).test(value)) return `must match ${constraints.pattern}`;
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
case PropertyValueType.Number: {
|
|
37
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) return 'expected a number';
|
|
38
|
+
if (constraints.integer && !Number.isInteger(value)) return 'expected a whole number';
|
|
39
|
+
if (constraints.minimum !== undefined && value < constraints.minimum) return `must be at least ${constraints.minimum}`;
|
|
40
|
+
if (constraints.maximum !== undefined && value > constraints.maximum) return `must be at most ${constraints.maximum}`;
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
case PropertyValueType.Boolean:
|
|
45
|
+
return typeof value === 'boolean' ? undefined : 'expected true or false';
|
|
46
|
+
|
|
47
|
+
case PropertyValueType.Enum:
|
|
48
|
+
return (descriptor.choices ?? []).some(choice => choice.value === value) ? undefined : 'not one of the allowed choices';
|
|
49
|
+
|
|
50
|
+
case PropertyValueType.Icon:
|
|
51
|
+
if (!isRecord(value) || !isNonEmptyString(value.library) || !isNonEmptyString(value.key)) return 'expected an icon reference with a library and a key';
|
|
52
|
+
return value.variant === undefined || typeof value.variant === 'string' ? undefined : 'the icon variant must be a string';
|
|
53
|
+
|
|
54
|
+
case PropertyValueType.Destination:
|
|
55
|
+
if (!isRecord(value) || !isNonEmptyString(value.screen)) return 'expected a destination naming a screen';
|
|
56
|
+
return value.routeParameterBindings === undefined || isRecord(value.routeParameterBindings)
|
|
57
|
+
? undefined
|
|
58
|
+
: 'routeParameterBindings must be an object';
|
|
59
|
+
|
|
60
|
+
case PropertyValueType.QueryReference:
|
|
61
|
+
if (isNonEmptyString(value)) return undefined;
|
|
62
|
+
if (!isRecord(value) || !isNonEmptyString(value.queryId) || !isNonEmptyString(value.query)) return 'expected a query name or a query binding';
|
|
63
|
+
return Array.isArray(value.arguments) && Array.isArray(value.results) ? undefined : 'a query binding needs arguments and results lists';
|
|
64
|
+
|
|
65
|
+
case PropertyValueType.Collection:
|
|
66
|
+
return validateCollection(descriptor, value);
|
|
67
|
+
|
|
68
|
+
default:
|
|
69
|
+
return isRecord(value) || Array.isArray(value) ? undefined : 'expected a structured value';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function validateCollection(descriptor: PropertyDescriptor, value: unknown): string | undefined {
|
|
74
|
+
if (!Array.isArray(value)) return 'expected a list';
|
|
75
|
+
const constraints = descriptor.constraints ?? {};
|
|
76
|
+
if (constraints.minimumItems !== undefined && value.length < constraints.minimumItems) return `needs at least ${constraints.minimumItems} items`;
|
|
77
|
+
if (constraints.maximumItems !== undefined && value.length > constraints.maximumItems) return `allows at most ${constraints.maximumItems} items`;
|
|
78
|
+
|
|
79
|
+
const identities = new Set<string>();
|
|
80
|
+
for (const item of value) {
|
|
81
|
+
if (!isRecord(item) || !isNonEmptyString(item.id)) return 'every item needs an id';
|
|
82
|
+
if (identities.has(item.id)) return `the item id '${item.id}' is used twice`;
|
|
83
|
+
identities.add(item.id);
|
|
84
|
+
|
|
85
|
+
const { id: _identity, ...values } = item;
|
|
86
|
+
const problem = validateItemValues(descriptor.item, values).at(0);
|
|
87
|
+
if (problem) return `item '${item.id}': ${problem.field} ${problem.problem}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* One field of a collection item that does not fit its descriptor.
|
|
95
|
+
*/
|
|
96
|
+
export interface ItemFieldProblem {
|
|
97
|
+
field: string;
|
|
98
|
+
problem: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Checks a collection item's field values against the collection's item descriptor.
|
|
103
|
+
*
|
|
104
|
+
* @param itemDescriptor What the items look like.
|
|
105
|
+
* @param values The item's field values, keyed by field path.
|
|
106
|
+
* @returns Every field that is unknown or has an unacceptable value.
|
|
107
|
+
*/
|
|
108
|
+
export function validateItemValues(itemDescriptor: CollectionItemDescriptor | undefined, values: Record<string, unknown>): ItemFieldProblem[] {
|
|
109
|
+
const fields = itemDescriptor?.properties ?? [];
|
|
110
|
+
const problems: ItemFieldProblem[] = [];
|
|
111
|
+
|
|
112
|
+
for (const [field, fieldValue] of Object.entries(values)) {
|
|
113
|
+
const fieldDescriptor = fields.find(candidate => candidate.path === field);
|
|
114
|
+
if (!fieldDescriptor) {
|
|
115
|
+
problems.push({ field, problem: 'is not a field of this collection\'s items' });
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const problem = validateValue(fieldDescriptor, fieldValue);
|
|
120
|
+
if (problem) problems.push({ field, problem });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (const fieldDescriptor of fields) {
|
|
124
|
+
if (fieldDescriptor.constraints?.required && values[fieldDescriptor.path] === undefined) {
|
|
125
|
+
problems.push({ field: fieldDescriptor.path, problem: 'a value is required' });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return problems;
|
|
130
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
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 { IconEntry, IconReference, formatIconReference } from '@cratis/scene.model';
|
|
5
|
+
import { EffectiveIconEntry, referencesOfEntry } from './EffectiveIconEntry';
|
|
6
|
+
import { IconCatalogSource } from './IconCatalogSource';
|
|
7
|
+
import { IconDiagnostic } from './IconDiagnostic';
|
|
8
|
+
import { IconLibraryResolution } from './IconLibraryResolution';
|
|
9
|
+
import { IconQuery } from './IconQuery';
|
|
10
|
+
import { IconResolution } from './IconResolution';
|
|
11
|
+
import { IconSearchResult } from './IconSearchResult';
|
|
12
|
+
import { ResolvedIconLibrary } from './ResolvedIconLibrary';
|
|
13
|
+
import { matchesIconQuery } from './matchesIconQuery';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The icons a profile can actually use: the active libraries from {@link resolveIconLibraries}, with their
|
|
17
|
+
* catalogs loaded on demand.
|
|
18
|
+
*
|
|
19
|
+
* Opening it costs nothing - no catalog is read until a query or a lookup needs that library, and a
|
|
20
|
+
* query narrowed to one library reads only that one. A catalog is loaded once and kept; a load that
|
|
21
|
+
* fails is not kept, so the next call tries again. Everything that goes wrong is reported as an
|
|
22
|
+
* {@link IconDiagnostic}; nothing is ever answered with a different icon than the one asked for.
|
|
23
|
+
*/
|
|
24
|
+
export class EffectiveIconCatalog {
|
|
25
|
+
readonly #sources: Map<string, IconCatalogSource>;
|
|
26
|
+
readonly #loads = new Map<string, Promise<IconEntry[]>>();
|
|
27
|
+
readonly #loadedEntries = new Map<string, IconEntry[]>();
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param resolution The active libraries and the problems found with them.
|
|
31
|
+
* @param sources The catalog source of each library; a library with none is active but reports
|
|
32
|
+
* 'catalog-unavailable' when its icons are needed.
|
|
33
|
+
*/
|
|
34
|
+
constructor(readonly resolution: IconLibraryResolution, sources: IconCatalogSource[]) {
|
|
35
|
+
this.#sources = new Map(sources.map((source) => [source.library, source]));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The active libraries, with provenance.
|
|
40
|
+
*/
|
|
41
|
+
get libraries(): ResolvedIconLibrary[] {
|
|
42
|
+
return this.resolution.libraries;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Problems with the libraries themselves, known without loading any catalog.
|
|
47
|
+
*/
|
|
48
|
+
get diagnostics(): IconDiagnostic[] {
|
|
49
|
+
return this.resolution.diagnostics;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Whether a library's catalog has been read yet.
|
|
54
|
+
*/
|
|
55
|
+
isLoaded(library: string): boolean {
|
|
56
|
+
return this.#loadedEntries.has(library);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The entries of one library, loading its catalog if this is the first time it is needed.
|
|
61
|
+
* Resolves to `undefined` when the library is not active.
|
|
62
|
+
*
|
|
63
|
+
* @throws Whatever the library's source throws, or an Error when an active library has no source.
|
|
64
|
+
*/
|
|
65
|
+
async entriesOf(library: string): Promise<IconEntry[] | undefined> {
|
|
66
|
+
if (!this.libraries.some((resolved) => resolved.library === library)) return undefined;
|
|
67
|
+
|
|
68
|
+
let load = this.#loads.get(library);
|
|
69
|
+
if (!load) {
|
|
70
|
+
const source = this.#sources.get(library);
|
|
71
|
+
if (!source) throw new Error(`The icon library '${library}' is active but has no catalog source`);
|
|
72
|
+
|
|
73
|
+
load = source.loadEntries();
|
|
74
|
+
this.#loads.set(library, load);
|
|
75
|
+
load.then(
|
|
76
|
+
(entries) => this.#loadedEntries.set(library, entries),
|
|
77
|
+
() => this.#loads.delete(library)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return load;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Searches the catalogs of the libraries the query covers - all of them, or the one it names.
|
|
86
|
+
*/
|
|
87
|
+
async search(query: IconQuery = {}): Promise<IconSearchResult> {
|
|
88
|
+
const covered = this.libraries.filter((resolved) => query.library === undefined || resolved.library === query.library);
|
|
89
|
+
const outcomes = await Promise.all(covered.map(async (resolved) => this.#entriesOrDiagnostic(resolved)));
|
|
90
|
+
|
|
91
|
+
const entries: EffectiveIconEntry[] = [];
|
|
92
|
+
const diagnostics: IconDiagnostic[] = [];
|
|
93
|
+
outcomes.forEach((outcome, position) => {
|
|
94
|
+
const library = covered[position];
|
|
95
|
+
if ('diagnostic' in outcome) {
|
|
96
|
+
diagnostics.push(outcome.diagnostic);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const entry of outcome.entries.filter((candidate) => matchesIconQuery(candidate, query))) {
|
|
101
|
+
entries.push({ library, entry, references: referencesOfEntry(library.library, entry) });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return { entries, diagnostics };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Every active library's icons whose name or key is exactly `name` (ignoring case) - the several
|
|
110
|
+
* candidates a bare legacy icon name could have meant. More than one is a real answer, not a tie to
|
|
111
|
+
* break: it is the author's decision which library the icon comes from.
|
|
112
|
+
*/
|
|
113
|
+
async findByName(name: string): Promise<EffectiveIconEntry[]> {
|
|
114
|
+
const wanted = name.trim().toLowerCase();
|
|
115
|
+
const { entries } = await this.search({});
|
|
116
|
+
return entries.filter(({ entry }) => entry.key.toLowerCase() === wanted || entry.name.toLowerCase() === wanted);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The categories in use, sorted, across all libraries or one.
|
|
121
|
+
*/
|
|
122
|
+
async categories(library?: string): Promise<string[]> {
|
|
123
|
+
const { entries } = await this.search({ library });
|
|
124
|
+
return [...new Set(entries.flatMap(({ entry }) => entry.categories))].sort();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Looks a reference up: the icon it names, or exactly why there is none.
|
|
129
|
+
*/
|
|
130
|
+
async resolve(reference: IconReference): Promise<IconResolution> {
|
|
131
|
+
const library = this.libraries.find((resolved) => resolved.library === reference.library);
|
|
132
|
+
if (library && !this.isLoaded(library.library) && !this.#incompatibility(library)) {
|
|
133
|
+
const outcome = await this.#entriesOrDiagnostic(library);
|
|
134
|
+
if ('diagnostic' in outcome) return { isResolved: false, reference, diagnostic: { ...outcome.diagnostic, reference } };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return this.lookup(reference) as IconResolution;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Looks a reference up without loading anything, for callers that cannot wait - an edit is applied
|
|
142
|
+
* synchronously. Resolves everything that is decidable from what is already known: a library that is not
|
|
143
|
+
* active, one at an incompatible version, and - once the library's catalog has been loaded - a missing
|
|
144
|
+
* icon or variant.
|
|
145
|
+
*
|
|
146
|
+
* @returns The resolution, or `undefined` when the library is active but its catalog has not been loaded,
|
|
147
|
+
* so nothing can be said about the icon yet. Call {@link load} first to make the answer definite.
|
|
148
|
+
*/
|
|
149
|
+
lookup(reference: IconReference): IconResolution | undefined {
|
|
150
|
+
const library = this.libraries.find((resolved) => resolved.library === reference.library);
|
|
151
|
+
if (!library) {
|
|
152
|
+
return this.#unresolved(reference, 'missing-library', `The icon library '${reference.library}' is not active in this profile`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const incompatible = this.#incompatibility(library);
|
|
156
|
+
if (incompatible) return { isResolved: false, reference, diagnostic: { ...incompatible, reference } };
|
|
157
|
+
|
|
158
|
+
const entries = this.#loadedEntries.get(library.library);
|
|
159
|
+
if (!entries) return undefined;
|
|
160
|
+
|
|
161
|
+
const entry = entries.find((candidate) => candidate.key === reference.key);
|
|
162
|
+
if (!entry) {
|
|
163
|
+
return this.#unresolved(reference, 'missing-icon', `The icon library '${library.library}' has no icon '${reference.key}'`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (reference.variant !== undefined && !(entry.variants ?? []).includes(reference.variant)) {
|
|
167
|
+
return this.#unresolved(reference, 'missing-variant', `The icon '${formatIconReference({ library: library.library, key: entry.key })}' has no '${reference.variant}' variant`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { isResolved: true, reference, library, entry };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Loads the catalogs of one library, or of every active library, so that {@link lookup} can answer
|
|
175
|
+
* definitely. Libraries whose catalog cannot be loaded are reported, not thrown.
|
|
176
|
+
*/
|
|
177
|
+
async load(library?: string): Promise<IconDiagnostic[]> {
|
|
178
|
+
const covered = this.libraries.filter((resolved) => library === undefined || resolved.library === library);
|
|
179
|
+
const outcomes = await Promise.all(covered.map(async (resolved) => this.#entriesOrDiagnostic(resolved)));
|
|
180
|
+
return outcomes.flatMap((outcome) => ('diagnostic' in outcome ? [outcome.diagnostic] : []));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
#incompatibility(library: ResolvedIconLibrary): IconDiagnostic | undefined {
|
|
184
|
+
return this.diagnostics.find((diagnostic) => diagnostic.kind === 'incompatible-version' && diagnostic.library === library.library);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async #entriesOrDiagnostic(library: ResolvedIconLibrary): Promise<{ entries: IconEntry[] } | { diagnostic: IconDiagnostic }> {
|
|
188
|
+
try {
|
|
189
|
+
return { entries: (await this.entriesOf(library.library)) ?? [] };
|
|
190
|
+
} catch (error) {
|
|
191
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
192
|
+
return { diagnostic: { kind: 'catalog-unavailable', library: library.library, message: `The catalog of '${library.library}' could not be loaded: ${reason}` } };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#unresolved(reference: IconReference, kind: IconDiagnostic['kind'], message: string): IconResolution & { isResolved: false } {
|
|
197
|
+
return { isResolved: false, reference, diagnostic: { kind, library: reference.library, message, reference } };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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 { IconEntry, IconReference } from '@cratis/scene.model';
|
|
5
|
+
import { ResolvedIconLibrary } from './ResolvedIconLibrary';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An icon as a picker shows it: the catalog entry, the library that provides it (so provenance and
|
|
9
|
+
* attribution are one step away), and the references that name it.
|
|
10
|
+
*/
|
|
11
|
+
export interface EffectiveIconEntry {
|
|
12
|
+
/**
|
|
13
|
+
* The active library that provides the icon.
|
|
14
|
+
*/
|
|
15
|
+
library: ResolvedIconLibrary;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The catalog entry.
|
|
19
|
+
*/
|
|
20
|
+
entry: IconEntry;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* One reference per variant the icon exists in, or the single variant-less reference when it has none.
|
|
24
|
+
*/
|
|
25
|
+
references: IconReference[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The references that name an entry of a library: one per variant, or one without a variant.
|
|
30
|
+
*/
|
|
31
|
+
export function referencesOfEntry(library: string, entry: IconEntry): IconReference[] {
|
|
32
|
+
const variants = entry.variants ?? [];
|
|
33
|
+
return variants.length === 0
|
|
34
|
+
? [{ library, key: entry.key }]
|
|
35
|
+
: variants.map((variant) => ({ library, key: entry.key, variant }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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 { IconEntry } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Where one icon library's catalog comes from. The library's module provides it; the engine only asks
|
|
8
|
+
* for it when something needs the library's icons, so resolving a profile never loads a catalog.
|
|
9
|
+
*
|
|
10
|
+
* A source supplies metadata only. The artwork for each icon is loaded separately, per icon, by the
|
|
11
|
+
* renderer's adapter for the library.
|
|
12
|
+
*/
|
|
13
|
+
export interface IconCatalogSource {
|
|
14
|
+
/**
|
|
15
|
+
* The library the catalog belongs to.
|
|
16
|
+
*/
|
|
17
|
+
library: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Loads the library's icon entries. Called at most once per successful load.
|
|
21
|
+
*/
|
|
22
|
+
loadEntries(): Promise<IconEntry[]>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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 { IconReference } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* What can be wrong with an icon library or an icon reference. Each is a distinct, reportable condition -
|
|
8
|
+
* none of them is ever resolved by quietly substituting another icon.
|
|
9
|
+
*/
|
|
10
|
+
export type IconDiagnosticKind =
|
|
11
|
+
/** The reference names a library that is not active in the profile. */
|
|
12
|
+
| 'missing-library'
|
|
13
|
+
/** The library is active but its catalog has no icon with the reference's key. */
|
|
14
|
+
| 'missing-icon'
|
|
15
|
+
/** The icon exists but not in the variant the reference asks for. */
|
|
16
|
+
| 'missing-variant'
|
|
17
|
+
/** The library is active but at a version a package that needs it does not accept. */
|
|
18
|
+
| 'incompatible-version'
|
|
19
|
+
/** The library is active but its catalog could not be loaded. */
|
|
20
|
+
| 'catalog-unavailable';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* One finding about an icon library or reference, carrying enough to explain it to an author.
|
|
24
|
+
*/
|
|
25
|
+
export interface IconDiagnostic {
|
|
26
|
+
/**
|
|
27
|
+
* What kind of problem this is.
|
|
28
|
+
*/
|
|
29
|
+
kind: IconDiagnosticKind;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The library the finding is about.
|
|
33
|
+
*/
|
|
34
|
+
library: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A sentence an author can act on.
|
|
38
|
+
*/
|
|
39
|
+
message: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The reference the finding is about, when it is about one reference rather than a whole library.
|
|
43
|
+
*/
|
|
44
|
+
reference?: IconReference;
|
|
45
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
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 { EffectiveIconEntry } from './EffectiveIconEntry';
|
|
5
|
+
import { IconDiagnostic } from './IconDiagnostic';
|
|
6
|
+
import { IconUsage } from './IconUsage';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A reference the proposed change would leave without an icon.
|
|
10
|
+
*/
|
|
11
|
+
export interface AffectedIconUsage {
|
|
12
|
+
/**
|
|
13
|
+
* The usage that would break.
|
|
14
|
+
*/
|
|
15
|
+
usage: IconUsage;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Why it would no longer resolve.
|
|
19
|
+
*/
|
|
20
|
+
diagnostic: IconDiagnostic;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether it resolved before the change. `false` marks a reference that was already broken, so a
|
|
24
|
+
* report can tell new damage from old.
|
|
25
|
+
*/
|
|
26
|
+
wasResolvable: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A legacy bare icon string the report leaves untouched, with the icons it could be migrated to.
|
|
31
|
+
*/
|
|
32
|
+
export interface LegacyIconUsage {
|
|
33
|
+
/**
|
|
34
|
+
* The usage holding the legacy string.
|
|
35
|
+
*/
|
|
36
|
+
usage: IconUsage;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The icons in the proposed catalog whose name or key equals the string. Empty means nothing to
|
|
40
|
+
* migrate to; more than one means the author has to choose a library.
|
|
41
|
+
*/
|
|
42
|
+
candidates: EffectiveIconEntry[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* What a library change would do to a set of persisted icon values. It describes; it never rewrites.
|
|
47
|
+
*/
|
|
48
|
+
export interface IconImpactReport {
|
|
49
|
+
/**
|
|
50
|
+
* References that resolve now (or did) and would not after the change.
|
|
51
|
+
*/
|
|
52
|
+
affected: AffectedIconUsage[];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* How many references resolve after the change.
|
|
56
|
+
*/
|
|
57
|
+
unaffectedCount: number;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Legacy strings, which are neither affected nor rewritten by a library change.
|
|
61
|
+
*/
|
|
62
|
+
legacy: LegacyIconUsage[];
|
|
63
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 { IconDiagnostic } from './IconDiagnostic';
|
|
5
|
+
import { ResolvedIconLibrary } from './ResolvedIconLibrary';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The icon libraries a set of packages makes active, and what is wrong with them.
|
|
9
|
+
*/
|
|
10
|
+
export interface IconLibraryResolution {
|
|
11
|
+
/**
|
|
12
|
+
* Every active icon library - selected or required transitively - in the dependency order of
|
|
13
|
+
* {@link resolvePackageDependencies}. Order carries no precedence: libraries coexist, and the library
|
|
14
|
+
* is part of every icon's identity.
|
|
15
|
+
*/
|
|
16
|
+
libraries: ResolvedIconLibrary[];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Problems with the libraries themselves, such as a version a dependent does not accept.
|
|
20
|
+
*/
|
|
21
|
+
diagnostics: IconDiagnostic[];
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* What a picker asks the effective catalog for. Every field narrows; an empty query returns everything.
|
|
6
|
+
*/
|
|
7
|
+
export interface IconQuery {
|
|
8
|
+
/**
|
|
9
|
+
* Free text, matched case-insensitively against each icon's name, key, aliases and tags.
|
|
10
|
+
*/
|
|
11
|
+
text?: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Only the icons of this library. Narrowing to one library also means only that library's catalog is loaded.
|
|
15
|
+
*/
|
|
16
|
+
library?: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Only the icons filed under this category.
|
|
20
|
+
*/
|
|
21
|
+
category?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Only the icons that exist in this variant.
|
|
25
|
+
*/
|
|
26
|
+
variant?: string;
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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 { IconEntry, IconReference } from '@cratis/scene.model';
|
|
5
|
+
import { IconDiagnostic } from './IconDiagnostic';
|
|
6
|
+
import { ResolvedIconLibrary } from './ResolvedIconLibrary';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The outcome of looking one reference up in the effective catalog: either the icon it names, or the
|
|
10
|
+
* precise reason there is none.
|
|
11
|
+
*/
|
|
12
|
+
export type IconResolution =
|
|
13
|
+
| {
|
|
14
|
+
/** The reference resolved. */
|
|
15
|
+
isResolved: true;
|
|
16
|
+
reference: IconReference;
|
|
17
|
+
library: ResolvedIconLibrary;
|
|
18
|
+
entry: IconEntry;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
/** The reference did not resolve. */
|
|
22
|
+
isResolved: false;
|
|
23
|
+
reference: IconReference;
|
|
24
|
+
diagnostic: IconDiagnostic;
|
|
25
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
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 { EffectiveIconEntry } from './EffectiveIconEntry';
|
|
5
|
+
import { IconDiagnostic } from './IconDiagnostic';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The outcome of querying the effective catalog.
|
|
9
|
+
*/
|
|
10
|
+
export interface IconSearchResult {
|
|
11
|
+
/**
|
|
12
|
+
* The icons that matched, library by library in resolution order and in each catalog's own order.
|
|
13
|
+
*/
|
|
14
|
+
entries: EffectiveIconEntry[];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Libraries whose catalog could not be loaded and so contributed nothing - reported rather than
|
|
18
|
+
* dropped, so an absent icon is never mistaken for one that does not exist.
|
|
19
|
+
*/
|
|
20
|
+
diagnostics: IconDiagnostic[];
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 { IconReference } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One place an icon is used - a persisted value somewhere in a screen, template, blueprint or profile.
|
|
8
|
+
*/
|
|
9
|
+
export interface IconUsage {
|
|
10
|
+
/**
|
|
11
|
+
* The icon value as persisted: an {@link IconReference}, or a legacy bare string (an icon font class
|
|
12
|
+
* such as `pi pi-home`) from before icons were library-qualified.
|
|
13
|
+
*/
|
|
14
|
+
value: IconReference | string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Where the value lives, in whatever terms the caller wants reported back (a screen name, a path).
|
|
18
|
+
* Never interpreted.
|
|
19
|
+
*/
|
|
20
|
+
location?: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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 { ScenePackage } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* An icon library that is active in a profile, with the reason it is.
|
|
8
|
+
*/
|
|
9
|
+
export interface ResolvedIconLibrary {
|
|
10
|
+
/**
|
|
11
|
+
* The library's identity - what an {@link IconReference.library} names.
|
|
12
|
+
*/
|
|
13
|
+
library: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The package declaration behind the library: version, license, attribution, renderers.
|
|
17
|
+
*/
|
|
18
|
+
package: ScenePackage;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether the profile lists the library itself. `false` means it is only active because something
|
|
22
|
+
* else needs it.
|
|
23
|
+
*/
|
|
24
|
+
isSelected: boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The names of the active packages that declare a dependency on the library. Together with
|
|
28
|
+
* {@link isSelected} this is the library's provenance: why it is here, and what stops depending on it
|
|
29
|
+
* when it is removed.
|
|
30
|
+
*/
|
|
31
|
+
requiredBy: string[];
|
|
32
|
+
}
|