@cratis/scene.engine 4.11.0 → 4.13.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/forms/CommandFormLayoutDiagnosticCode.js +20 -0
- package/dist/cjs/forms/CommandFormLayoutDiagnosticCode.js.map +1 -0
- package/dist/cjs/forms/commitCommandFormLayoutDraft.js +12 -0
- package/dist/cjs/forms/commitCommandFormLayoutDraft.js.map +1 -0
- package/dist/cjs/forms/defaultCommandFormLayout.js +23 -0
- package/dist/cjs/forms/defaultCommandFormLayout.js.map +1 -0
- package/dist/cjs/forms/formWidthToCss.js +24 -0
- package/dist/cjs/forms/formWidthToCss.js.map +1 -0
- package/dist/cjs/forms/normalizeCommandFormLayout.js +42 -0
- package/dist/cjs/forms/normalizeCommandFormLayout.js.map +1 -0
- package/dist/cjs/forms/parseFormWidth.js +34 -0
- package/dist/cjs/forms/parseFormWidth.js.map +1 -0
- package/dist/cjs/forms/preserveDirtyCommandValues.js +15 -0
- package/dist/cjs/forms/preserveDirtyCommandValues.js.map +1 -0
- package/dist/cjs/forms/resizeCommandFormColumn.js +27 -0
- package/dist/cjs/forms/resizeCommandFormColumn.js.map +1 -0
- package/dist/cjs/forms/updateCommandFormFieldPlacement.js +27 -0
- package/dist/cjs/forms/updateCommandFormFieldPlacement.js.map +1 -0
- package/dist/cjs/forms/validateCommandFormLayout.js +72 -0
- package/dist/cjs/forms/validateCommandFormLayout.js.map +1 -0
- package/dist/cjs/index.js +40 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/navigation/NavigationDiagnosticCode.js +19 -0
- package/dist/cjs/navigation/NavigationDiagnosticCode.js.map +1 -0
- package/dist/cjs/navigation/collectOutlets.js +45 -0
- package/dist/cjs/navigation/collectOutlets.js.map +1 -0
- package/dist/cjs/navigation/diagnoseNavigation.js +116 -0
- package/dist/cjs/navigation/diagnoseNavigation.js.map +1 -0
- package/dist/cjs/navigation/findHostingCycles.js +43 -0
- package/dist/cjs/navigation/findHostingCycles.js.map +1 -0
- package/dist/cjs/navigation/navigationEntriesFrom.js +19 -0
- package/dist/cjs/navigation/navigationEntriesFrom.js.map +1 -0
- package/dist/cjs/navigation/navigationRoute.js +25 -0
- package/dist/cjs/navigation/navigationRoute.js.map +1 -0
- package/dist/cjs/packageVersionRange.js +16 -0
- package/dist/cjs/packageVersionRange.js.map +1 -1
- package/dist/cjs/templates/TemplateCatalogKind.js +15 -0
- package/dist/cjs/templates/TemplateCatalogKind.js.map +1 -0
- package/dist/cjs/templates/describeTemplateCatalog.js +89 -0
- package/dist/cjs/templates/describeTemplateCatalog.js.map +1 -0
- package/dist/cjs/templates/templateMetadataRules.js +32 -0
- package/dist/cjs/templates/templateMetadataRules.js.map +1 -0
- package/dist/cjs/templates/validateTemplateMetadata.js +50 -0
- package/dist/cjs/templates/validateTemplateMetadata.js.map +1 -0
- package/dist/cjs/validateNavigationDestinations.js +12 -38
- package/dist/cjs/validateNavigationDestinations.js.map +1 -1
- package/dist/esm/forms/CommandFormLayoutDiagnostic.d.ts +7 -0
- package/dist/esm/forms/CommandFormLayoutDiagnostic.d.ts.map +1 -0
- package/dist/esm/forms/CommandFormLayoutDiagnostic.js +2 -0
- package/dist/esm/forms/CommandFormLayoutDiagnostic.js.map +1 -0
- package/dist/esm/forms/CommandFormLayoutDiagnosticCode.d.ts +11 -0
- package/dist/esm/forms/CommandFormLayoutDiagnosticCode.d.ts.map +1 -0
- package/dist/esm/forms/CommandFormLayoutDiagnosticCode.js +18 -0
- package/dist/esm/forms/CommandFormLayoutDiagnosticCode.js.map +1 -0
- package/dist/esm/forms/CommandFormLayoutDraft.d.ts +9 -0
- package/dist/esm/forms/CommandFormLayoutDraft.d.ts.map +1 -0
- package/dist/esm/forms/CommandFormLayoutDraft.js +2 -0
- package/dist/esm/forms/CommandFormLayoutDraft.js.map +1 -0
- package/dist/esm/forms/commitCommandFormLayoutDraft.d.ts +4 -0
- package/dist/esm/forms/commitCommandFormLayoutDraft.d.ts.map +1 -0
- package/dist/esm/forms/commitCommandFormLayoutDraft.js +10 -0
- package/dist/esm/forms/commitCommandFormLayoutDraft.js.map +1 -0
- package/dist/esm/forms/defaultCommandFormLayout.d.ts +3 -0
- package/dist/esm/forms/defaultCommandFormLayout.d.ts.map +1 -0
- package/dist/esm/forms/defaultCommandFormLayout.js +21 -0
- package/dist/esm/forms/defaultCommandFormLayout.js.map +1 -0
- package/dist/esm/forms/formWidthToCss.d.ts +3 -0
- package/dist/esm/forms/formWidthToCss.d.ts.map +1 -0
- package/dist/esm/forms/formWidthToCss.js +22 -0
- package/dist/esm/forms/formWidthToCss.js.map +1 -0
- package/dist/esm/forms/index.d.ts +13 -0
- package/dist/esm/forms/index.d.ts.map +1 -0
- package/dist/esm/forms/index.js +13 -0
- package/dist/esm/forms/index.js.map +1 -0
- package/dist/esm/forms/normalizeCommandFormLayout.d.ts +8 -0
- package/dist/esm/forms/normalizeCommandFormLayout.d.ts.map +1 -0
- package/dist/esm/forms/normalizeCommandFormLayout.js +40 -0
- package/dist/esm/forms/normalizeCommandFormLayout.js.map +1 -0
- package/dist/esm/forms/parseFormWidth.d.ts +3 -0
- package/dist/esm/forms/parseFormWidth.d.ts.map +1 -0
- package/dist/esm/forms/parseFormWidth.js +32 -0
- package/dist/esm/forms/parseFormWidth.js.map +1 -0
- package/dist/esm/forms/preserveDirtyCommandValues.d.ts +2 -0
- package/dist/esm/forms/preserveDirtyCommandValues.d.ts.map +1 -0
- package/dist/esm/forms/preserveDirtyCommandValues.js +13 -0
- package/dist/esm/forms/preserveDirtyCommandValues.js.map +1 -0
- package/dist/esm/forms/resizeCommandFormColumn.d.ts +4 -0
- package/dist/esm/forms/resizeCommandFormColumn.d.ts.map +1 -0
- package/dist/esm/forms/resizeCommandFormColumn.js +25 -0
- package/dist/esm/forms/resizeCommandFormColumn.js.map +1 -0
- package/dist/esm/forms/updateCommandFormFieldPlacement.d.ts +4 -0
- package/dist/esm/forms/updateCommandFormFieldPlacement.d.ts.map +1 -0
- package/dist/esm/forms/updateCommandFormFieldPlacement.js +25 -0
- package/dist/esm/forms/updateCommandFormFieldPlacement.js.map +1 -0
- package/dist/esm/forms/validateCommandFormLayout.d.ts +4 -0
- package/dist/esm/forms/validateCommandFormLayout.d.ts.map +1 -0
- package/dist/esm/forms/validateCommandFormLayout.js +70 -0
- package/dist/esm/forms/validateCommandFormLayout.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +19 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/navigation/NavigationDiagnostic.d.ts +7 -0
- package/dist/esm/navigation/NavigationDiagnostic.d.ts.map +1 -0
- package/dist/esm/navigation/NavigationDiagnostic.js +2 -0
- package/dist/esm/navigation/NavigationDiagnostic.js.map +1 -0
- package/dist/esm/navigation/NavigationDiagnosticCode.d.ts +9 -0
- package/dist/esm/navigation/NavigationDiagnosticCode.d.ts.map +1 -0
- package/dist/esm/navigation/NavigationDiagnosticCode.js +17 -0
- package/dist/esm/navigation/NavigationDiagnosticCode.js.map +1 -0
- package/dist/esm/navigation/NavigationEntry.d.ts +6 -0
- package/dist/esm/navigation/NavigationEntry.d.ts.map +1 -0
- package/dist/esm/navigation/NavigationEntry.js +2 -0
- package/dist/esm/navigation/NavigationEntry.js.map +1 -0
- package/dist/esm/navigation/NavigationGraph.d.ts +10 -0
- package/dist/esm/navigation/NavigationGraph.d.ts.map +1 -0
- package/dist/esm/navigation/NavigationGraph.js +2 -0
- package/dist/esm/navigation/NavigationGraph.js.map +1 -0
- package/dist/esm/navigation/OutletOwner.d.ts +7 -0
- package/dist/esm/navigation/OutletOwner.d.ts.map +1 -0
- package/dist/esm/navigation/OutletOwner.js +2 -0
- package/dist/esm/navigation/OutletOwner.js.map +1 -0
- package/dist/esm/navigation/collectOutlets.d.ts +5 -0
- package/dist/esm/navigation/collectOutlets.d.ts.map +1 -0
- package/dist/esm/navigation/collectOutlets.js +43 -0
- package/dist/esm/navigation/collectOutlets.js.map +1 -0
- package/dist/esm/navigation/diagnoseNavigation.d.ts +5 -0
- package/dist/esm/navigation/diagnoseNavigation.d.ts.map +1 -0
- package/dist/esm/navigation/diagnoseNavigation.js +114 -0
- package/dist/esm/navigation/diagnoseNavigation.js.map +1 -0
- package/dist/esm/navigation/findHostingCycles.d.ts +2 -0
- package/dist/esm/navigation/findHostingCycles.d.ts.map +1 -0
- package/dist/esm/navigation/findHostingCycles.js +41 -0
- package/dist/esm/navigation/findHostingCycles.js.map +1 -0
- package/dist/esm/navigation/index.d.ts +8 -0
- package/dist/esm/navigation/index.d.ts.map +1 -0
- package/dist/esm/navigation/index.js +8 -0
- package/dist/esm/navigation/index.js.map +1 -0
- package/dist/esm/navigation/navigationEntriesFrom.d.ts +4 -0
- package/dist/esm/navigation/navigationEntriesFrom.d.ts.map +1 -0
- package/dist/esm/navigation/navigationEntriesFrom.js +17 -0
- package/dist/esm/navigation/navigationEntriesFrom.js.map +1 -0
- package/dist/esm/navigation/navigationRoute.d.ts +5 -0
- package/dist/esm/navigation/navigationRoute.d.ts.map +1 -0
- package/dist/esm/navigation/navigationRoute.js +22 -0
- package/dist/esm/navigation/navigationRoute.js.map +1 -0
- package/dist/esm/packageVersionRange.d.ts +2 -0
- package/dist/esm/packageVersionRange.d.ts.map +1 -1
- package/dist/esm/packageVersionRange.js +15 -1
- package/dist/esm/packageVersionRange.js.map +1 -1
- package/dist/esm/templates/TemplateCatalogEntry.d.ts +20 -0
- package/dist/esm/templates/TemplateCatalogEntry.d.ts.map +1 -0
- package/dist/esm/templates/TemplateCatalogEntry.js +2 -0
- package/dist/esm/templates/TemplateCatalogEntry.js.map +1 -0
- package/dist/esm/templates/TemplateCatalogKind.d.ts +6 -0
- package/dist/esm/templates/TemplateCatalogKind.d.ts.map +1 -0
- package/dist/esm/templates/TemplateCatalogKind.js +13 -0
- package/dist/esm/templates/TemplateCatalogKind.js.map +1 -0
- package/dist/esm/templates/TemplateSource.d.ts +8 -0
- package/dist/esm/templates/TemplateSource.d.ts.map +1 -0
- package/dist/esm/templates/TemplateSource.js +2 -0
- package/dist/esm/templates/TemplateSource.js.map +1 -0
- package/dist/esm/templates/describeTemplateCatalog.d.ts +4 -0
- package/dist/esm/templates/describeTemplateCatalog.d.ts.map +1 -0
- package/dist/esm/templates/describeTemplateCatalog.js +87 -0
- package/dist/esm/templates/describeTemplateCatalog.js.map +1 -0
- package/dist/esm/templates/index.d.ts +7 -0
- package/dist/esm/templates/index.d.ts.map +1 -0
- package/dist/esm/templates/index.js +7 -0
- package/dist/esm/templates/index.js.map +1 -0
- package/dist/esm/templates/templateMetadataRules.d.ts +3 -0
- package/dist/esm/templates/templateMetadataRules.d.ts.map +1 -0
- package/dist/esm/templates/templateMetadataRules.js +29 -0
- package/dist/esm/templates/templateMetadataRules.js.map +1 -0
- package/dist/esm/templates/validateTemplateMetadata.d.ts +3 -0
- package/dist/esm/templates/validateTemplateMetadata.d.ts.map +1 -0
- package/dist/esm/templates/validateTemplateMetadata.js +48 -0
- package/dist/esm/templates/validateTemplateMetadata.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/validateNavigationDestinations.d.ts +5 -5
- package/dist/esm/validateNavigationDestinations.d.ts.map +1 -1
- package/dist/esm/validateNavigationDestinations.js +12 -38
- package/dist/esm/validateNavigationDestinations.js.map +1 -1
- package/forms/CommandFormLayoutDiagnostic.ts +13 -0
- package/forms/CommandFormLayoutDiagnosticCode.ts +16 -0
- package/forms/CommandFormLayoutDraft.ts +15 -0
- package/forms/commitCommandFormLayoutDraft.ts +12 -0
- package/forms/defaultCommandFormLayout.ts +12 -0
- package/forms/formWidthToCss.ts +21 -0
- package/forms/index.ts +15 -0
- package/forms/normalizeCommandFormLayout.ts +39 -0
- package/forms/parseFormWidth.ts +20 -0
- package/forms/preserveDirtyCommandValues.ts +13 -0
- package/forms/resizeCommandFormColumn.ts +23 -0
- package/forms/updateCommandFormFieldPlacement.ts +22 -0
- package/forms/validateCommandFormLayout.ts +74 -0
- package/index.ts +3 -0
- package/navigation/NavigationDiagnostic.ts +18 -0
- package/navigation/NavigationDiagnosticCode.ts +26 -0
- package/navigation/NavigationEntry.ts +16 -0
- package/navigation/NavigationGraph.ts +26 -0
- package/navigation/OutletOwner.ts +13 -0
- package/navigation/collectOutlets.ts +36 -0
- package/navigation/diagnoseNavigation.ts +136 -0
- package/navigation/findHostingCycles.ts +41 -0
- package/navigation/index.ts +10 -0
- package/navigation/navigationEntriesFrom.ts +16 -0
- package/navigation/navigationRoute.ts +25 -0
- package/package.json +3 -3
- package/packageVersionRange.ts +18 -0
- package/templates/TemplateCatalogEntry.ts +35 -0
- package/templates/TemplateCatalogKind.ts +11 -0
- package/templates/TemplateSource.ts +15 -0
- package/templates/describeTemplateCatalog.ts +92 -0
- package/templates/index.ts +9 -0
- package/templates/templateMetadataRules.ts +25 -0
- package/templates/validateTemplateMetadata.ts +55 -0
- package/validateNavigationDestinations.ts +12 -32
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { DestinationReference, Layout, ScreenTemplate } from '@cratis/scene.model';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
message: string;
|
|
5
|
-
}
|
|
1
|
+
import { DestinationReference, DialogTemplate, Layout, Screen, ScreenTemplate } from '@cratis/scene.model';
|
|
2
|
+
import { NavigationDiagnostic } from './navigation';
|
|
3
|
+
export type NavigationDestinationDiagnostic = NavigationDiagnostic;
|
|
6
4
|
export declare function validateNavigationDestinations(destinations: DestinationReference[], surfaces?: {
|
|
7
5
|
layouts?: Layout[];
|
|
8
6
|
screenTemplates?: ScreenTemplate[];
|
|
7
|
+
screens?: Screen[];
|
|
8
|
+
dialogTemplates?: DialogTemplate[];
|
|
9
9
|
}): NavigationDestinationDiagnostic[];
|
|
10
10
|
//# sourceMappingURL=validateNavigationDestinations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateNavigationDestinations.d.ts","sourceRoot":"","sources":["../../validateNavigationDestinations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"validateNavigationDestinations.d.ts","sourceRoot":"","sources":["../../validateNavigationDestinations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,oBAAoB,EAAsB,MAAM,cAAc,CAAC;AAKxE,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CAAC;AAQnE,wBAAgB,8BAA8B,CAC1C,YAAY,EAAE,oBAAoB,EAAE,EACpC,QAAQ,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAA;CAAO,GAClI,+BAA+B,EAAE,CAEnC"}
|
|
@@ -1,45 +1,19 @@
|
|
|
1
|
+
import { diagnoseNavigation } from './navigation/diagnoseNavigation.js';
|
|
2
|
+
|
|
1
3
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
4
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
5
|
/**
|
|
4
|
-
* Validates destinations against the outlet/route declarations owned by layouts and templates
|
|
6
|
+
* Validates destinations against the outlet/route declarations owned by layouts and templates, and - when
|
|
7
|
+
* the screens and dialog templates are given - against the targets that actually exist.
|
|
8
|
+
*
|
|
9
|
+
* A shorthand for {@link diagnoseNavigation} over destinations without entry identities.
|
|
5
10
|
*/ function validateNavigationDestinations(destinations, surfaces = {}) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
...surfaces
|
|
11
|
-
|
|
12
|
-
]){
|
|
13
|
-
for (const outlet of surface.outlets ?? []){
|
|
14
|
-
if (outlets.has(outlet.name)) diagnostics.push({
|
|
15
|
-
code: 'duplicateOutlet',
|
|
16
|
-
message: `Outlet '${outlet.name}' is declared more than once.`
|
|
17
|
-
});
|
|
18
|
-
outlets.add(outlet.name);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
for (const destination of destinations){
|
|
22
|
-
if (destination.outlet && !outlets.has(destination.outlet)) {
|
|
23
|
-
diagnostics.push({
|
|
24
|
-
code: 'missingOutlet',
|
|
25
|
-
message: `Destination targets missing outlet '${destination.outlet}'.`
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
if (destination.route) {
|
|
29
|
-
if (routes.has(destination.route)) diagnostics.push({
|
|
30
|
-
code: 'duplicateRoute',
|
|
31
|
-
message: `Route '${destination.route}' is used by more than one destination.`
|
|
32
|
-
});
|
|
33
|
-
routes.add(destination.route);
|
|
34
|
-
}
|
|
35
|
-
if (!destination.screen && !destination.module && !destination.route && !destination.dialog) {
|
|
36
|
-
diagnostics.push({
|
|
37
|
-
code: 'unavailableTarget',
|
|
38
|
-
message: 'Destination must name a screen, stable identity, route or dialog.'
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return diagnostics;
|
|
11
|
+
return diagnoseNavigation({
|
|
12
|
+
entries: destinations.map((destination)=>({
|
|
13
|
+
destination
|
|
14
|
+
})),
|
|
15
|
+
...surfaces
|
|
16
|
+
});
|
|
43
17
|
}
|
|
44
18
|
|
|
45
19
|
export { validateNavigationDestinations };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateNavigationDestinations.js","sources":["../../validateNavigationDestinations.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 { DestinationReference, Layout, ScreenTemplate } from '@cratis/scene.model';\n\
|
|
1
|
+
{"version":3,"file":"validateNavigationDestinations.js","sources":["../../validateNavigationDestinations.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 { DestinationReference, DialogTemplate, Layout, Screen, ScreenTemplate } from '@cratis/scene.model';\nimport { NavigationDiagnostic, diagnoseNavigation } from './navigation';\n\n/**\n * A navigation problem as {@link validateNavigationDestinations} reports it.\n */\nexport type NavigationDestinationDiagnostic = NavigationDiagnostic;\n\n/**\n * Validates destinations against the outlet/route declarations owned by layouts and templates, and - when\n * the screens and dialog templates are given - against the targets that actually exist.\n *\n * A shorthand for {@link diagnoseNavigation} over destinations without entry identities.\n */\nexport function validateNavigationDestinations(\n destinations: DestinationReference[],\n surfaces: { layouts?: Layout[]; screenTemplates?: ScreenTemplate[]; screens?: Screen[]; dialogTemplates?: DialogTemplate[] } = {},\n): NavigationDestinationDiagnostic[] {\n return diagnoseNavigation({ entries: destinations.map(destination => ({ destination })), ...surfaces });\n}\n"],"names":["validateNavigationDestinations","destinations","surfaces","diagnoseNavigation","entries","map","destination"],"mappings":";;AAAA;AACA;AAUA;;;;;AAKC,IACM,SAASA,8BAAAA,CACZC,YAAoC,EACpCC,QAAAA,GAA+H,EAAE,EAAA;AAEjI,IAAA,OAAOC,kBAAAA,CAAmB;AAAEC,QAAAA,OAAAA,EAASH,YAAAA,CAAaI,GAAG,CAACC,CAAAA,eAAgB;AAAEA,gBAAAA;aAAY,CAAA,CAAA;AAAK,QAAA,GAAGJ;AAAS,KAAA,CAAA;AACzG;;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 { CommandFormLayoutDiagnosticCode } from './CommandFormLayoutDiagnosticCode';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A validation problem in authored command-form geometry.
|
|
8
|
+
*/
|
|
9
|
+
export interface CommandFormLayoutDiagnostic {
|
|
10
|
+
code: CommandFormLayoutDiagnosticCode;
|
|
11
|
+
message: string;
|
|
12
|
+
path: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
* Diagnostic codes for command-form geometry validation.
|
|
6
|
+
*/
|
|
7
|
+
export enum CommandFormLayoutDiagnosticCode {
|
|
8
|
+
EmptyColumns = 'emptyColumns',
|
|
9
|
+
DuplicateColumn = 'duplicateColumn',
|
|
10
|
+
InvalidColumnIndex = 'invalidColumnIndex',
|
|
11
|
+
InvalidWidth = 'invalidWidth',
|
|
12
|
+
DuplicatePlacement = 'duplicatePlacement',
|
|
13
|
+
InvalidPlacement = 'invalidPlacement',
|
|
14
|
+
MissingField = 'missingField',
|
|
15
|
+
OutOfBoundsPlacement = 'outOfBoundsPlacement',
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
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 { CommandFormLayout } from '@cratis/scene.model';
|
|
5
|
+
import { CommandFormLayoutDiagnostic } from './CommandFormLayoutDiagnostic';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Separates invalid editing state from the last committed form geometry.
|
|
9
|
+
*/
|
|
10
|
+
export interface CommandFormLayoutDraft {
|
|
11
|
+
committed: CommandFormLayout;
|
|
12
|
+
draft: CommandFormLayout;
|
|
13
|
+
diagnostics: CommandFormLayoutDiagnostic[];
|
|
14
|
+
isValid: boolean;
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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 { CommandFormLayout } from '@cratis/scene.model';
|
|
5
|
+
import { CommandFormLayoutDraft } from './CommandFormLayoutDraft';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Commits a draft layout only when it is valid; otherwise returns the previous committed metadata.
|
|
9
|
+
*/
|
|
10
|
+
export function commitCommandFormLayoutDraft(draft: CommandFormLayoutDraft): CommandFormLayout {
|
|
11
|
+
return draft.isValid ? draft.draft : draft.committed;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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 { CommandFormLayout, FormWidthUnit } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Backward-compatible command form geometry: one flexible column and no authored placements.
|
|
8
|
+
*/
|
|
9
|
+
export const defaultCommandFormLayout: CommandFormLayout = {
|
|
10
|
+
columns: [{ index: 1, width: { unit: FormWidthUnit.Fraction, value: 1 } }],
|
|
11
|
+
placements: [],
|
|
12
|
+
};
|
|
@@ -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 { FormWidth, FormWidthUnit } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Converts a platform-neutral form width to a browser CSS width token.
|
|
8
|
+
*/
|
|
9
|
+
export function formWidthToCss(width: FormWidth | undefined): string | undefined {
|
|
10
|
+
if (!width) return undefined;
|
|
11
|
+
switch (width.unit) {
|
|
12
|
+
case FormWidthUnit.Auto:
|
|
13
|
+
return 'auto';
|
|
14
|
+
case FormWidthUnit.Fraction:
|
|
15
|
+
return `${width.value ?? 1}fr`;
|
|
16
|
+
case FormWidthUnit.Pixels:
|
|
17
|
+
return `${width.value ?? 0}px`;
|
|
18
|
+
case FormWidthUnit.Percent:
|
|
19
|
+
return `${width.value ?? 0}%`;
|
|
20
|
+
}
|
|
21
|
+
}
|
package/forms/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
export * from './CommandFormLayoutDiagnostic';
|
|
5
|
+
export * from './CommandFormLayoutDiagnosticCode';
|
|
6
|
+
export * from './CommandFormLayoutDraft';
|
|
7
|
+
export * from './commitCommandFormLayoutDraft';
|
|
8
|
+
export * from './defaultCommandFormLayout';
|
|
9
|
+
export * from './formWidthToCss';
|
|
10
|
+
export * from './normalizeCommandFormLayout';
|
|
11
|
+
export * from './parseFormWidth';
|
|
12
|
+
export * from './preserveDirtyCommandValues';
|
|
13
|
+
export * from './resizeCommandFormColumn';
|
|
14
|
+
export * from './updateCommandFormFieldPlacement';
|
|
15
|
+
export * from './validateCommandFormLayout';
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { CommandFormLayout, FormColumn, FormFieldPlacement, FormWidth, FormWidthUnit } from '@cratis/scene.model';
|
|
5
|
+
import { defaultCommandFormLayout } from './defaultCommandFormLayout';
|
|
6
|
+
import { parseFormWidth } from './parseFormWidth';
|
|
7
|
+
|
|
8
|
+
export interface LegacyCommandFormInputGeometry {
|
|
9
|
+
property: string;
|
|
10
|
+
column?: number;
|
|
11
|
+
width?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes authored command form layout, including legacy per-input column/width metadata.
|
|
16
|
+
*/
|
|
17
|
+
export function normalizeCommandFormLayout(layout: CommandFormLayout | undefined, inputs: readonly LegacyCommandFormInputGeometry[] = []): CommandFormLayout {
|
|
18
|
+
if (layout) return layout;
|
|
19
|
+
if (!inputs.length) return defaultCommandFormLayout;
|
|
20
|
+
const placements = inputs.map((input, index): FormFieldPlacement => ({
|
|
21
|
+
field: input.property,
|
|
22
|
+
row: index + 1,
|
|
23
|
+
column: positiveInteger(input.column) ?? 1,
|
|
24
|
+
width: parseFormWidth(input.width),
|
|
25
|
+
}));
|
|
26
|
+
const columnCount = Math.max(1, ...placements.map(placement => placement.column));
|
|
27
|
+
return {
|
|
28
|
+
columns: Array.from({ length: columnCount }, (_, index): FormColumn => ({ index: index + 1, width: fraction(1) })),
|
|
29
|
+
placements,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function fraction(value: number): FormWidth {
|
|
34
|
+
return { unit: FormWidthUnit.Fraction, value };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function positiveInteger(value: number | undefined): number | undefined {
|
|
38
|
+
return value !== undefined && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { FormWidth, FormWidthUnit } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parses a legacy width token into typed form geometry. Arbitrary strings are intentionally rejected.
|
|
8
|
+
*/
|
|
9
|
+
export function parseFormWidth(value: unknown): FormWidth | undefined {
|
|
10
|
+
if (!value || typeof value !== 'string') return undefined;
|
|
11
|
+
const trimmed = value.trim();
|
|
12
|
+
if (trimmed === 'auto') return { unit: FormWidthUnit.Auto };
|
|
13
|
+
const match = /^([0-9]+(?:\.[0-9]+)?)(fr|px|%)$/.exec(trimmed);
|
|
14
|
+
if (!match) return undefined;
|
|
15
|
+
const widthValue = Number(match[1]);
|
|
16
|
+
if (!Number.isFinite(widthValue) || widthValue < 0) return undefined;
|
|
17
|
+
if (match[2] === 'fr') return { unit: FormWidthUnit.Fraction, value: widthValue };
|
|
18
|
+
if (match[2] === 'px') return { unit: FormWidthUnit.Pixels, value: widthValue };
|
|
19
|
+
return { unit: FormWidthUnit.Percent, value: widthValue };
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
+
* Merges refreshed command values without overwriting dirty fields a user is editing.
|
|
6
|
+
*/
|
|
7
|
+
export function preserveDirtyCommandValues(
|
|
8
|
+
current: Record<string, unknown>,
|
|
9
|
+
refreshed: Record<string, unknown>,
|
|
10
|
+
dirtyFields: ReadonlySet<string>,
|
|
11
|
+
): Record<string, unknown> {
|
|
12
|
+
return Object.fromEntries(Object.entries(refreshed).map(([field, value]) => [field, dirtyFields.has(field) ? current[field] : value]));
|
|
13
|
+
}
|
|
@@ -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 { CommandFormLayout, FormWidth } from '@cratis/scene.model';
|
|
5
|
+
import { CommandFormLayoutDraft } from './CommandFormLayoutDraft';
|
|
6
|
+
import { validateCommandFormLayout } from './validateCommandFormLayout';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resizes a column as draft geometry, keeping the last committed layout separate when invalid.
|
|
10
|
+
*/
|
|
11
|
+
export function resizeCommandFormColumn(
|
|
12
|
+
committed: CommandFormLayout,
|
|
13
|
+
columnIndex: number,
|
|
14
|
+
width: FormWidth,
|
|
15
|
+
fields: readonly string[] = [],
|
|
16
|
+
): CommandFormLayoutDraft {
|
|
17
|
+
const draft: CommandFormLayout = {
|
|
18
|
+
...committed,
|
|
19
|
+
columns: committed.columns.map(column => column.index === columnIndex ? { ...column, width } : column),
|
|
20
|
+
};
|
|
21
|
+
const diagnostics = validateCommandFormLayout(draft, fields);
|
|
22
|
+
return { committed, draft, diagnostics, isValid: diagnostics.length === 0 };
|
|
23
|
+
}
|
|
@@ -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 { CommandFormLayout, FormFieldPlacement } from '@cratis/scene.model';
|
|
5
|
+
import { CommandFormLayoutDraft } from './CommandFormLayoutDraft';
|
|
6
|
+
import { validateCommandFormLayout } from './validateCommandFormLayout';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Updates a field placement as draft geometry, keeping the committed layout separate when invalid.
|
|
10
|
+
*/
|
|
11
|
+
export function updateCommandFormFieldPlacement(
|
|
12
|
+
committed: CommandFormLayout,
|
|
13
|
+
placement: FormFieldPlacement,
|
|
14
|
+
fields: readonly string[] = [],
|
|
15
|
+
): CommandFormLayoutDraft {
|
|
16
|
+
const draft: CommandFormLayout = {
|
|
17
|
+
...committed,
|
|
18
|
+
placements: [...committed.placements.filter(existing => existing.field !== placement.field), placement],
|
|
19
|
+
};
|
|
20
|
+
const diagnostics = validateCommandFormLayout(draft, fields);
|
|
21
|
+
return { committed, draft, diagnostics, isValid: diagnostics.length === 0 };
|
|
22
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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 { CommandFormLayout, FormWidth, FormWidthUnit } from '@cratis/scene.model';
|
|
5
|
+
import { CommandFormLayoutDiagnostic } from './CommandFormLayoutDiagnostic';
|
|
6
|
+
import { CommandFormLayoutDiagnosticCode } from './CommandFormLayoutDiagnosticCode';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validates authored command-form geometry without rewriting invalid drafts.
|
|
10
|
+
*/
|
|
11
|
+
export function validateCommandFormLayout(layout: CommandFormLayout, fields: readonly string[] = []): CommandFormLayoutDiagnostic[] {
|
|
12
|
+
const diagnostics: CommandFormLayoutDiagnostic[] = [];
|
|
13
|
+
const columnIndexes = new Set<number>();
|
|
14
|
+
const knownFields = new Set(fields);
|
|
15
|
+
|
|
16
|
+
if (!layout.columns.length) diagnostics.push(problem(CommandFormLayoutDiagnosticCode.EmptyColumns, 'At least one column is required.', 'columns'));
|
|
17
|
+
layout.columns.forEach((column, index) => {
|
|
18
|
+
if (!Number.isInteger(column.index) || column.index < 1) {
|
|
19
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.InvalidColumnIndex, `Column ${index + 1} must have a one-based integer index.`, `columns.${index}.index`));
|
|
20
|
+
}
|
|
21
|
+
if (columnIndexes.has(column.index)) {
|
|
22
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.DuplicateColumn, `Column ${column.index} is declared more than once.`, `columns.${index}.index`));
|
|
23
|
+
}
|
|
24
|
+
columnIndexes.add(column.index);
|
|
25
|
+
validateWidth(column.width, `columns.${index}.width`, diagnostics);
|
|
26
|
+
validateWidth(column.minWidth, `columns.${index}.minWidth`, diagnostics);
|
|
27
|
+
validateWidth(column.maxWidth, `columns.${index}.maxWidth`, diagnostics);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
validateWidth(layout.columnGap, 'columnGap', diagnostics);
|
|
31
|
+
validateWidth(layout.rowGap, 'rowGap', diagnostics);
|
|
32
|
+
|
|
33
|
+
const placements = new Set<string>();
|
|
34
|
+
layout.placements.forEach((placement, index) => {
|
|
35
|
+
if (!placement.field.trim()) diagnostics.push(problem(CommandFormLayoutDiagnosticCode.MissingField, 'A placement must name its field.', `placements.${index}.field`));
|
|
36
|
+
if (knownFields.size && !knownFields.has(placement.field)) {
|
|
37
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.MissingField, `Placement targets unknown field '${placement.field}'.`, `placements.${index}.field`));
|
|
38
|
+
}
|
|
39
|
+
if (placements.has(placement.field)) {
|
|
40
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.DuplicatePlacement, `Field '${placement.field}' is placed more than once.`, `placements.${index}.field`));
|
|
41
|
+
}
|
|
42
|
+
placements.add(placement.field);
|
|
43
|
+
if (!Number.isInteger(placement.row) || placement.row < 1 || !Number.isInteger(placement.column) || placement.column < 1 ||
|
|
44
|
+
(placement.rowSpan !== undefined && (!Number.isInteger(placement.rowSpan) || placement.rowSpan < 1)) ||
|
|
45
|
+
(placement.columnSpan !== undefined && (!Number.isInteger(placement.columnSpan) || placement.columnSpan < 1))) {
|
|
46
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.InvalidPlacement, `Placement for '${placement.field}' must use positive integer row, column and span values.`, `placements.${index}`));
|
|
47
|
+
}
|
|
48
|
+
const span = placement.columnSpan ?? 1;
|
|
49
|
+
if (layout.columns.length && placement.column + span - 1 > layout.columns.length) {
|
|
50
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.OutOfBoundsPlacement, `Placement for '${placement.field}' extends beyond the declared columns.`, `placements.${index}.columnSpan`));
|
|
51
|
+
}
|
|
52
|
+
validateWidth(placement.width, `placements.${index}.width`, diagnostics);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return diagnostics;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function validateWidth(width: FormWidth | undefined, path: string, diagnostics: CommandFormLayoutDiagnostic[]): void {
|
|
59
|
+
if (!width) return;
|
|
60
|
+
if (!Object.values(FormWidthUnit).includes(width.unit)) {
|
|
61
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.InvalidWidth, `Width at '${path}' uses an unsupported unit.`, path));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (width.unit === FormWidthUnit.Auto && width.value !== undefined) {
|
|
65
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.InvalidWidth, `Automatic width at '${path}' must not carry a numeric value.`, path));
|
|
66
|
+
}
|
|
67
|
+
if (width.unit !== FormWidthUnit.Auto && (width.value === undefined || width.value < 0 || !Number.isFinite(width.value))) {
|
|
68
|
+
diagnostics.push(problem(CommandFormLayoutDiagnosticCode.InvalidWidth, `Width at '${path}' must carry a non-negative numeric value.`, path));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function problem(code: CommandFormLayoutDiagnosticCode, message: string, path: string): CommandFormLayoutDiagnostic {
|
|
73
|
+
return { code, message, path };
|
|
74
|
+
}
|
package/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './BindingDiagnostic';
|
|
|
8
8
|
export * from './resolveBindingExpression';
|
|
9
9
|
export * from './validateBindingExpression';
|
|
10
10
|
export * from './renderElement';
|
|
11
|
+
export * from './forms';
|
|
11
12
|
export * from './elementKind';
|
|
12
13
|
export * from './panelKind';
|
|
13
14
|
export * from './flowNodeKind';
|
|
@@ -26,11 +27,13 @@ export * from './resolvePackageDependencies';
|
|
|
26
27
|
export * from './packageCatalog';
|
|
27
28
|
export * from './resolveScreenTemplates';
|
|
28
29
|
export * from './templateApplicability';
|
|
30
|
+
export * from './templates';
|
|
29
31
|
export * from './buildStarterProfile';
|
|
30
32
|
export * from './incompatibleStarterThemes';
|
|
31
33
|
export * from './ActionDispatcher';
|
|
32
34
|
export * from './runActions';
|
|
33
35
|
export * from './resolveBehaviors';
|
|
34
36
|
export * from './resolveStrings';
|
|
37
|
+
export * from './navigation';
|
|
35
38
|
export * from './validateNavigationDestinations';
|
|
36
39
|
export * from './editing';
|
|
@@ -0,0 +1,18 @@
|
|
|
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 { NavigationDiagnosticCode } from './NavigationDiagnosticCode';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One problem with how destinations, outlets and routes fit together.
|
|
8
|
+
*/
|
|
9
|
+
export interface NavigationDiagnostic {
|
|
10
|
+
/** What kind of problem this is. */
|
|
11
|
+
code: NavigationDiagnosticCode;
|
|
12
|
+
|
|
13
|
+
/** A sentence naming the destinations, outlets or screens involved. */
|
|
14
|
+
message: string;
|
|
15
|
+
|
|
16
|
+
/** The entry the problem was found on - its `id`, or `#<position>` when it has none. Absent for model-wide problems. */
|
|
17
|
+
entry?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
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 is wrong with a navigation destination. The values are shared with the C# engine so both report
|
|
6
|
+
* the same code for the same model.
|
|
7
|
+
*/
|
|
8
|
+
export enum NavigationDiagnosticCode {
|
|
9
|
+
/** Two destinations that go to different targets share one URL. */
|
|
10
|
+
DuplicateRoute = 'duplicateRoute',
|
|
11
|
+
|
|
12
|
+
/** Two surfaces declare an outlet with the same name, so a destination cannot tell them apart. */
|
|
13
|
+
DuplicateOutlet = 'duplicateOutlet',
|
|
14
|
+
|
|
15
|
+
/** A destination names an outlet that no layout or screen template declares. */
|
|
16
|
+
MissingOutlet = 'missingOutlet',
|
|
17
|
+
|
|
18
|
+
/** A destination names an outlet that cannot host what it opens. */
|
|
19
|
+
IncompatibleOutlet = 'incompatibleOutlet',
|
|
20
|
+
|
|
21
|
+
/** Screens are placed in outlets owned by each other, so composition never terminates. */
|
|
22
|
+
NavigationCycle = 'navigationCycle',
|
|
23
|
+
|
|
24
|
+
/** A destination opens a screen or dialog that does not exist, or names nothing to open. */
|
|
25
|
+
UnavailableTarget = 'unavailableTarget',
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
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 { DestinationReference } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One place in the model a user can navigate from - a navigation item, toolbar action or link - reduced to
|
|
8
|
+
* its stable identity and destination.
|
|
9
|
+
*/
|
|
10
|
+
export interface NavigationEntry {
|
|
11
|
+
/** Stable identity used to point at the entry in diagnostics. */
|
|
12
|
+
id?: string;
|
|
13
|
+
|
|
14
|
+
/** Where the entry takes the user. */
|
|
15
|
+
destination: DestinationReference;
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
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 { DialogTemplate, Layout, Screen, ScreenTemplate } from '@cratis/scene.model';
|
|
5
|
+
import { NavigationEntry } from './NavigationEntry';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Everything navigation diagnostics look at. The catalogs are optional: an absent catalog means "not known
|
|
9
|
+
* here", so targets in it are not reported as unavailable. An empty catalog means "known to be empty".
|
|
10
|
+
*/
|
|
11
|
+
export interface NavigationGraph {
|
|
12
|
+
/** The destinations to check, in authored order. */
|
|
13
|
+
entries: NavigationEntry[];
|
|
14
|
+
|
|
15
|
+
/** The screens destinations may open. */
|
|
16
|
+
screens?: Screen[];
|
|
17
|
+
|
|
18
|
+
/** The layouts that may own outlets. */
|
|
19
|
+
layouts?: Layout[];
|
|
20
|
+
|
|
21
|
+
/** The screen templates that may own outlets, and that give screens their semantic type. */
|
|
22
|
+
screenTemplates?: ScreenTemplate[];
|
|
23
|
+
|
|
24
|
+
/** The dialog templates dialog destinations may open. */
|
|
25
|
+
dialogTemplates?: DialogTemplate[];
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 { Outlet } from '@cratis/scene.model';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* An outlet together with the layout or screen template that declares it.
|
|
8
|
+
*/
|
|
9
|
+
export interface OutletOwner {
|
|
10
|
+
outlet: Outlet;
|
|
11
|
+
owner: string;
|
|
12
|
+
ownerKind: 'Layout' | 'ScreenTemplate';
|
|
13
|
+
}
|
|
@@ -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 { NavigationDiagnostic } from './NavigationDiagnostic';
|
|
5
|
+
import { NavigationDiagnosticCode } from './NavigationDiagnosticCode';
|
|
6
|
+
import { NavigationGraph } from './NavigationGraph';
|
|
7
|
+
import { OutletOwner } from './OutletOwner';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Indexes every declared outlet by name, keeping the first declaration and reporting each later one as a
|
|
11
|
+
* duplicate - a destination names an outlet only by name, so two of them are ambiguous.
|
|
12
|
+
*/
|
|
13
|
+
export function collectOutlets(graph: NavigationGraph, diagnostics: NavigationDiagnostic[]): Map<string, OutletOwner> {
|
|
14
|
+
const owners = new Map<string, OutletOwner>();
|
|
15
|
+
const surfaces = [
|
|
16
|
+
...(graph.layouts ?? []).map(layout => ({ name: layout.name, kind: 'Layout' as const, outlets: layout.outlets ?? [] })),
|
|
17
|
+
...(graph.screenTemplates ?? []).map(template => ({ name: template.name, kind: 'ScreenTemplate' as const, outlets: template.outlets ?? [] })),
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
for (const surface of surfaces) {
|
|
21
|
+
for (const outlet of surface.outlets) {
|
|
22
|
+
const existing = owners.get(outlet.name);
|
|
23
|
+
if (existing) {
|
|
24
|
+
diagnostics.push({
|
|
25
|
+
code: NavigationDiagnosticCode.DuplicateOutlet,
|
|
26
|
+
message: `Outlet '${outlet.name}' is declared by both '${existing.owner}' and '${surface.name}'; destinations cannot tell them apart.`,
|
|
27
|
+
});
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
owners.set(outlet.name, { outlet, owner: surface.name, ownerKind: surface.kind });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return owners;
|
|
36
|
+
}
|