@ankhorage/contracts 7.1.0 → 7.2.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/CHANGELOG.md +6 -0
- package/dist/appManifest/bindings.d.ts +4 -0
- package/dist/appManifest/bindings.d.ts.map +1 -0
- package/dist/appManifest/bindings.js +96 -0
- package/dist/appManifest/bindings.js.map +1 -0
- package/dist/appManifest/dataSources.d.ts +2 -0
- package/dist/appManifest/dataSources.d.ts.map +1 -0
- package/dist/appManifest/dataSources.js +133 -0
- package/dist/appManifest/dataSources.js.map +1 -0
- package/dist/appManifest/generatedApis.d.ts +2 -0
- package/dist/appManifest/generatedApis.d.ts.map +1 -0
- package/dist/appManifest/generatedApis.js +87 -0
- package/dist/appManifest/generatedApis.js.map +1 -0
- package/dist/appManifest/infra.d.ts +2 -0
- package/dist/appManifest/infra.d.ts.map +1 -0
- package/dist/appManifest/infra.js +136 -0
- package/dist/appManifest/infra.js.map +1 -0
- package/dist/appManifest/screens.d.ts +6 -0
- package/dist/appManifest/screens.d.ts.map +1 -0
- package/dist/appManifest/screens.js +119 -0
- package/dist/appManifest/screens.js.map +1 -0
- package/dist/appManifest/shared.d.ts +8 -0
- package/dist/appManifest/shared.d.ts.map +1 -0
- package/dist/appManifest/shared.js +31 -0
- package/dist/appManifest/shared.js.map +1 -0
- package/dist/appManifest.d.ts +19 -0
- package/dist/appManifest.d.ts.map +1 -0
- package/dist/appManifest.js +64 -0
- package/dist/appManifest.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/appManifest/bindings.ts +135 -0
- package/src/appManifest/dataSources.ts +175 -0
- package/src/appManifest/generatedApis.ts +122 -0
- package/src/appManifest/infra.ts +199 -0
- package/src/appManifest/screens.ts +171 -0
- package/src/appManifest/shared.ts +40 -0
- package/src/appManifest.test.ts +185 -0
- package/src/appManifest.ts +86 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { COLOR_HARMONIES } from '@ankhorage/color-theory';
|
|
2
|
+
import { APP_CATEGORIES, NAVIGATOR_TYPES } from '../types';
|
|
3
|
+
import { isBindingValueSource, isScreenDataLoaderDefinition } from './bindings';
|
|
4
|
+
import { isOptionalBoolean, isOptionalNumber, isOptionalString, isRecord, isStringArray, } from './shared';
|
|
5
|
+
const APP_CATEGORY_SET = new Set(APP_CATEGORIES);
|
|
6
|
+
const COLOR_HARMONY_SET = new Set(COLOR_HARMONIES);
|
|
7
|
+
const NAVIGATOR_TYPE_SET = new Set(NAVIGATOR_TYPES);
|
|
8
|
+
const SPLASH_SCREEN_RESIZE_MODE_SET = new Set(['contain', 'cover', 'native']);
|
|
9
|
+
export function isManifestMetadata(value) {
|
|
10
|
+
return (isRecord(value) &&
|
|
11
|
+
typeof value.name === 'string' &&
|
|
12
|
+
typeof value.slug === 'string' &&
|
|
13
|
+
typeof value.version === 'string' &&
|
|
14
|
+
typeof value.category === 'string' &&
|
|
15
|
+
APP_CATEGORY_SET.has(value.category) &&
|
|
16
|
+
typeof value.themeId === 'string' &&
|
|
17
|
+
isOptionalString(value.created) &&
|
|
18
|
+
isOptionalString(value.updated));
|
|
19
|
+
}
|
|
20
|
+
export function isThemeConfig(value) {
|
|
21
|
+
return (isRecord(value) &&
|
|
22
|
+
typeof value.id === 'string' &&
|
|
23
|
+
typeof value.name === 'string' &&
|
|
24
|
+
isThemeModeConfig(value.light) &&
|
|
25
|
+
isThemeModeConfig(value.dark));
|
|
26
|
+
}
|
|
27
|
+
export function isNavigatorSpec(value) {
|
|
28
|
+
return (isRecord(value) &&
|
|
29
|
+
typeof value.type === 'string' &&
|
|
30
|
+
NAVIGATOR_TYPE_SET.has(value.type) &&
|
|
31
|
+
isOptionalString(value.initialRouteName) &&
|
|
32
|
+
Array.isArray(value.routes) &&
|
|
33
|
+
value.routes.every(isRouteDefinition) &&
|
|
34
|
+
(value.options === undefined || isRecord(value.options)));
|
|
35
|
+
}
|
|
36
|
+
export function isScreenRegistry(value) {
|
|
37
|
+
return (isRecord(value) &&
|
|
38
|
+
Object.entries(value).every(([registryKey, screen]) => isScreenSpec(screen) && isRecord(screen) && registryKey === screen.id));
|
|
39
|
+
}
|
|
40
|
+
export function isSplashScreenSpec(value) {
|
|
41
|
+
return (isSplashScreenModeSpec(value) &&
|
|
42
|
+
isRecord(value) &&
|
|
43
|
+
(value.dark === undefined || isSplashScreenModeSpec(value.dark)));
|
|
44
|
+
}
|
|
45
|
+
function isThemeModeConfig(value) {
|
|
46
|
+
return (isRecord(value) &&
|
|
47
|
+
typeof value.primaryColor === 'string' &&
|
|
48
|
+
typeof value.harmony === 'string' &&
|
|
49
|
+
COLOR_HARMONY_SET.has(value.harmony));
|
|
50
|
+
}
|
|
51
|
+
function isUiNode(value) {
|
|
52
|
+
return (isRecord(value) &&
|
|
53
|
+
typeof value.id === 'string' &&
|
|
54
|
+
typeof value.type === 'string' &&
|
|
55
|
+
isOptionalString(value.alias) &&
|
|
56
|
+
(value.props === undefined || isRecord(value.props)) &&
|
|
57
|
+
(value.style === undefined || isRecord(value.style)) &&
|
|
58
|
+
(value.repeat === undefined || isUiNodeRepeatSpec(value.repeat)) &&
|
|
59
|
+
(value.children === undefined ||
|
|
60
|
+
(Array.isArray(value.children) && value.children.every(isUiNode))));
|
|
61
|
+
}
|
|
62
|
+
function isUiNodeRepeatSpec(value) {
|
|
63
|
+
return (isRecord(value) &&
|
|
64
|
+
isBindingValueSource(value.source) &&
|
|
65
|
+
isOptionalString(value.itemAlias) &&
|
|
66
|
+
isOptionalString(value.keyPath) &&
|
|
67
|
+
(value.empty === undefined || (Array.isArray(value.empty) && value.empty.every(isUiNode))));
|
|
68
|
+
}
|
|
69
|
+
function isScreenSpec(value) {
|
|
70
|
+
return (isRecord(value) &&
|
|
71
|
+
typeof value.id === 'string' &&
|
|
72
|
+
typeof value.name === 'string' &&
|
|
73
|
+
isOptionalString(value.title) &&
|
|
74
|
+
isOptionalString(value.description) &&
|
|
75
|
+
(value.dataLoaders === undefined ||
|
|
76
|
+
(Array.isArray(value.dataLoaders) &&
|
|
77
|
+
value.dataLoaders.every(isScreenDataLoaderDefinition))) &&
|
|
78
|
+
(value.requires === undefined || isScreenRequirements(value.requires)) &&
|
|
79
|
+
isUiNode(value.root));
|
|
80
|
+
}
|
|
81
|
+
function isRouteDefinition(value) {
|
|
82
|
+
return (isRecord(value) &&
|
|
83
|
+
typeof value.name === 'string' &&
|
|
84
|
+
isOptionalString(value.path) &&
|
|
85
|
+
isOptionalString(value.label) &&
|
|
86
|
+
(value.icon === undefined || isIconSpec(value.icon)) &&
|
|
87
|
+
isOptionalBoolean(value.showInPrimaryNavigation) &&
|
|
88
|
+
(value.guards === undefined || isStringArray(value.guards)) &&
|
|
89
|
+
isOptionalString(value.screenId) &&
|
|
90
|
+
(value.navigator === undefined || isNavigatorSpec(value.navigator)));
|
|
91
|
+
}
|
|
92
|
+
function isIconSpec(value) {
|
|
93
|
+
return (isRecord(value) &&
|
|
94
|
+
typeof value.name === 'string' &&
|
|
95
|
+
isOptionalString(value.provider) &&
|
|
96
|
+
(value.size === undefined ||
|
|
97
|
+
typeof value.size === 'string' ||
|
|
98
|
+
typeof value.size === 'number') &&
|
|
99
|
+
isOptionalString(value.color));
|
|
100
|
+
}
|
|
101
|
+
function isSplashScreenModeSpec(value) {
|
|
102
|
+
return (isRecord(value) &&
|
|
103
|
+
isOptionalString(value.image) &&
|
|
104
|
+
isOptionalNumber(value.imageWidth) &&
|
|
105
|
+
(value.resizeMode === undefined ||
|
|
106
|
+
(typeof value.resizeMode === 'string' &&
|
|
107
|
+
SPLASH_SCREEN_RESIZE_MODE_SET.has(value.resizeMode))) &&
|
|
108
|
+
isOptionalString(value.backgroundColor));
|
|
109
|
+
}
|
|
110
|
+
function isScreenRequirements(value) {
|
|
111
|
+
return (isRecord(value) &&
|
|
112
|
+
(value.permissions === undefined || isRequirementArray(value.permissions, 'permission')) &&
|
|
113
|
+
(value.capabilities === undefined || isRequirementArray(value.capabilities, 'capability')));
|
|
114
|
+
}
|
|
115
|
+
function isRequirementArray(value, key) {
|
|
116
|
+
return (Array.isArray(value) &&
|
|
117
|
+
value.every((entry) => isRecord(entry) && typeof entry[key] === 'string'));
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=screens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screens.js","sourceRoot":"","sources":["../../src/appManifest/screens.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLOR_HARMONIES } from '@ankhorage/color-theory';\n\nimport { APP_CATEGORIES, NAVIGATOR_TYPES } from '../types';\nimport { isBindingValueSource, isScreenDataLoaderDefinition } from './bindings';\nimport {\n isOptionalBoolean,\n isOptionalNumber,\n isOptionalString,\n isRecord,\n isStringArray,\n} from './shared';\n\nconst APP_CATEGORY_SET = new Set<string>(APP_CATEGORIES);\nconst COLOR_HARMONY_SET = new Set<string>(COLOR_HARMONIES);\nconst NAVIGATOR_TYPE_SET = new Set<string>(NAVIGATOR_TYPES);\nconst SPLASH_SCREEN_RESIZE_MODE_SET = new Set<string>(['contain', 'cover', 'native']);\n\nexport function isManifestMetadata(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.name === 'string' &&\n typeof value.slug === 'string' &&\n typeof value.version === 'string' &&\n typeof value.category === 'string' &&\n APP_CATEGORY_SET.has(value.category) &&\n typeof value.themeId === 'string' &&\n isOptionalString(value.created) &&\n isOptionalString(value.updated)\n );\n}\n\nexport function isThemeConfig(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.id === 'string' &&\n typeof value.name === 'string' &&\n isThemeModeConfig(value.light) &&\n isThemeModeConfig(value.dark)\n );\n}\n\nexport function isNavigatorSpec(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.type === 'string' &&\n NAVIGATOR_TYPE_SET.has(value.type) &&\n isOptionalString(value.initialRouteName) &&\n Array.isArray(value.routes) &&\n value.routes.every(isRouteDefinition) &&\n (value.options === undefined || isRecord(value.options))\n );\n}\n\nexport function isScreenRegistry(value: unknown): boolean {\n return (\n isRecord(value) &&\n Object.entries(value).every(\n ([registryKey, screen]) =>\n isScreenSpec(screen) && isRecord(screen) && registryKey === screen.id,\n )\n );\n}\n\nexport function isSplashScreenSpec(value: unknown): boolean {\n return (\n isSplashScreenModeSpec(value) &&\n isRecord(value) &&\n (value.dark === undefined || isSplashScreenModeSpec(value.dark))\n );\n}\n\nfunction isThemeModeConfig(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.primaryColor === 'string' &&\n typeof value.harmony === 'string' &&\n COLOR_HARMONY_SET.has(value.harmony)\n );\n}\n\nfunction isUiNode(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.id === 'string' &&\n typeof value.type === 'string' &&\n isOptionalString(value.alias) &&\n (value.props === undefined || isRecord(value.props)) &&\n (value.style === undefined || isRecord(value.style)) &&\n (value.repeat === undefined || isUiNodeRepeatSpec(value.repeat)) &&\n (value.children === undefined ||\n (Array.isArray(value.children) && value.children.every(isUiNode)))\n );\n}\n\nfunction isUiNodeRepeatSpec(value: unknown): boolean {\n return (\n isRecord(value) &&\n isBindingValueSource(value.source) &&\n isOptionalString(value.itemAlias) &&\n isOptionalString(value.keyPath) &&\n (value.empty === undefined || (Array.isArray(value.empty) && value.empty.every(isUiNode)))\n );\n}\n\nfunction isScreenSpec(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.id === 'string' &&\n typeof value.name === 'string' &&\n isOptionalString(value.title) &&\n isOptionalString(value.description) &&\n (value.dataLoaders === undefined ||\n (Array.isArray(value.dataLoaders) &&\n value.dataLoaders.every(isScreenDataLoaderDefinition))) &&\n (value.requires === undefined || isScreenRequirements(value.requires)) &&\n isUiNode(value.root)\n );\n}\n\nfunction isRouteDefinition(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.name === 'string' &&\n isOptionalString(value.path) &&\n isOptionalString(value.label) &&\n (value.icon === undefined || isIconSpec(value.icon)) &&\n isOptionalBoolean(value.showInPrimaryNavigation) &&\n (value.guards === undefined || isStringArray(value.guards)) &&\n isOptionalString(value.screenId) &&\n (value.navigator === undefined || isNavigatorSpec(value.navigator))\n );\n}\n\nfunction isIconSpec(value: unknown): boolean {\n return (\n isRecord(value) &&\n typeof value.name === 'string' &&\n isOptionalString(value.provider) &&\n (value.size === undefined ||\n typeof value.size === 'string' ||\n typeof value.size === 'number') &&\n isOptionalString(value.color)\n );\n}\n\nfunction isSplashScreenModeSpec(value: unknown): boolean {\n return (\n isRecord(value) &&\n isOptionalString(value.image) &&\n isOptionalNumber(value.imageWidth) &&\n (value.resizeMode === undefined ||\n (typeof value.resizeMode === 'string' &&\n SPLASH_SCREEN_RESIZE_MODE_SET.has(value.resizeMode))) &&\n isOptionalString(value.backgroundColor)\n );\n}\n\nfunction isScreenRequirements(value: unknown): boolean {\n return (\n isRecord(value) &&\n (value.permissions === undefined || isRequirementArray(value.permissions, 'permission')) &&\n (value.capabilities === undefined || isRequirementArray(value.capabilities, 'capability'))\n );\n}\n\nfunction isRequirementArray(value: unknown, key: 'capability' | 'permission'): boolean {\n return (\n Array.isArray(value) &&\n value.every((entry) => isRecord(entry) && typeof entry[key] === 'string')\n );\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
2
|
+
export declare function isOptionalString(value: unknown): boolean;
|
|
3
|
+
export declare function isOptionalNumber(value: unknown): boolean;
|
|
4
|
+
export declare function isOptionalBoolean(value: unknown): boolean;
|
|
5
|
+
export declare function isStringArray(value: unknown): value is string[];
|
|
6
|
+
export declare function isStringRecord(value: unknown): boolean;
|
|
7
|
+
export declare function isManifestValue(value: unknown): boolean;
|
|
8
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/appManifest/shared.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAExD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAExD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,EAAE,CAE/D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAevD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function isOptionalString(value) {
|
|
5
|
+
return value === undefined || typeof value === 'string';
|
|
6
|
+
}
|
|
7
|
+
export function isOptionalNumber(value) {
|
|
8
|
+
return value === undefined || typeof value === 'number';
|
|
9
|
+
}
|
|
10
|
+
export function isOptionalBoolean(value) {
|
|
11
|
+
return value === undefined || typeof value === 'boolean';
|
|
12
|
+
}
|
|
13
|
+
export function isStringArray(value) {
|
|
14
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
|
|
15
|
+
}
|
|
16
|
+
export function isStringRecord(value) {
|
|
17
|
+
return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'string');
|
|
18
|
+
}
|
|
19
|
+
export function isManifestValue(value) {
|
|
20
|
+
if (value === null ||
|
|
21
|
+
typeof value === 'string' ||
|
|
22
|
+
typeof value === 'number' ||
|
|
23
|
+
typeof value === 'boolean') {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
return value.every(isManifestValue);
|
|
28
|
+
}
|
|
29
|
+
return isRecord(value) && Object.values(value).every(isManifestValue);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/appManifest/shared.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,SAAS,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IACE,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,KAAK,KAAK,SAAS,EAC1B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;AACxE,CAAC","sourcesContent":["export function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isOptionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string';\n}\n\nexport function isOptionalNumber(value: unknown): boolean {\n return value === undefined || typeof value === 'number';\n}\n\nexport function isOptionalBoolean(value: unknown): boolean {\n return value === undefined || typeof value === 'boolean';\n}\n\nexport function isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === 'string');\n}\n\nexport function isStringRecord(value: unknown): boolean {\n return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'string');\n}\n\nexport function isManifestValue(value: unknown): boolean {\n if (\n value === null ||\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.every(isManifestValue);\n }\n\n return isRecord(value) && Object.values(value).every(isManifestValue);\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AppManifest } from './types';
|
|
2
|
+
export type AppManifestParseResult = {
|
|
3
|
+
readonly ok: true;
|
|
4
|
+
readonly manifest: AppManifest;
|
|
5
|
+
} | {
|
|
6
|
+
readonly ok: false;
|
|
7
|
+
readonly message: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Parse unknown JSON-compatible input at the canonical AppManifest boundary.
|
|
11
|
+
*
|
|
12
|
+
* Contracts owns structural manifest validation. Consumers may add semantic
|
|
13
|
+
* diagnostics after this parser succeeds, but should not reconstruct the
|
|
14
|
+
* AppManifest shape in their own packages.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseAppManifest(value: unknown): AppManifestParseResult;
|
|
17
|
+
/** Return whether an unknown value satisfies the canonical AppManifest shape. */
|
|
18
|
+
export declare function isAppManifest(value: unknown): value is AppManifest;
|
|
19
|
+
//# sourceMappingURL=appManifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appManifest.d.ts","sourceRoot":"","sources":["../src/appManifest.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAiBrD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAIvE;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAkBlE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { isComponentDataBindingRegistry } from './appManifest/bindings';
|
|
2
|
+
import { isDataSourceRegistry } from './appManifest/dataSources';
|
|
3
|
+
import { isGeneratedApiRegistry } from './appManifest/generatedApis';
|
|
4
|
+
import { isInfraManifest } from './appManifest/infra';
|
|
5
|
+
import { isManifestMetadata, isNavigatorSpec, isScreenRegistry, isSplashScreenSpec, isThemeConfig, } from './appManifest/screens';
|
|
6
|
+
import { isOptionalString, isRecord, isStringArray } from './appManifest/shared';
|
|
7
|
+
const APP_MANIFEST_KEY_POLICY = {
|
|
8
|
+
metadata: 'required',
|
|
9
|
+
themes: 'required',
|
|
10
|
+
activeThemeId: 'required',
|
|
11
|
+
activeThemeMode: 'optional',
|
|
12
|
+
splashScreen: 'optional',
|
|
13
|
+
infra: 'required',
|
|
14
|
+
navigator: 'required',
|
|
15
|
+
screens: 'required',
|
|
16
|
+
generatedApis: 'optional',
|
|
17
|
+
dataSources: 'optional',
|
|
18
|
+
dataBindings: 'optional',
|
|
19
|
+
settings: 'required',
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Parse unknown JSON-compatible input at the canonical AppManifest boundary.
|
|
23
|
+
*
|
|
24
|
+
* Contracts owns structural manifest validation. Consumers may add semantic
|
|
25
|
+
* diagnostics after this parser succeeds, but should not reconstruct the
|
|
26
|
+
* AppManifest shape in their own packages.
|
|
27
|
+
*/
|
|
28
|
+
export function parseAppManifest(value) {
|
|
29
|
+
return isAppManifest(value)
|
|
30
|
+
? { ok: true, manifest: value }
|
|
31
|
+
: { ok: false, message: 'Value is not a canonical AppManifest.' };
|
|
32
|
+
}
|
|
33
|
+
/** Return whether an unknown value satisfies the canonical AppManifest shape. */
|
|
34
|
+
export function isAppManifest(value) {
|
|
35
|
+
return (isRecord(value) &&
|
|
36
|
+
hasRequiredManifestKeys(value) &&
|
|
37
|
+
isManifestMetadata(value.metadata) &&
|
|
38
|
+
Array.isArray(value.themes) &&
|
|
39
|
+
value.themes.every(isThemeConfig) &&
|
|
40
|
+
typeof value.activeThemeId === 'string' &&
|
|
41
|
+
isActiveThemeMode(value.activeThemeMode) &&
|
|
42
|
+
(value.splashScreen === undefined || isSplashScreenSpec(value.splashScreen)) &&
|
|
43
|
+
isInfraManifest(value.infra) &&
|
|
44
|
+
isNavigatorSpec(value.navigator) &&
|
|
45
|
+
isScreenRegistry(value.screens) &&
|
|
46
|
+
(value.generatedApis === undefined || isGeneratedApiRegistry(value.generatedApis)) &&
|
|
47
|
+
(value.dataSources === undefined || isDataSourceRegistry(value.dataSources)) &&
|
|
48
|
+
(value.dataBindings === undefined || isComponentDataBindingRegistry(value.dataBindings)) &&
|
|
49
|
+
isAppSettings(value.settings));
|
|
50
|
+
}
|
|
51
|
+
function hasRequiredManifestKeys(value) {
|
|
52
|
+
return Object.entries(APP_MANIFEST_KEY_POLICY).every(([key, policy]) => policy === 'optional' || key in value);
|
|
53
|
+
}
|
|
54
|
+
function isActiveThemeMode(value) {
|
|
55
|
+
return value === undefined || value === 'dark' || value === 'light';
|
|
56
|
+
}
|
|
57
|
+
function isAppSettings(value) {
|
|
58
|
+
return (isRecord(value) &&
|
|
59
|
+
isRecord(value.localization) &&
|
|
60
|
+
typeof value.localization.defaultLocale === 'string' &&
|
|
61
|
+
isStringArray(value.localization.locales) &&
|
|
62
|
+
isOptionalString(value.apiBaseUrl));
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=appManifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appManifest.js","sourceRoot":"","sources":["../src/appManifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAOjF,MAAM,uBAAuB,GAAG;IAC9B,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,UAAU;IAClB,aAAa,EAAE,UAAU;IACzB,eAAe,EAAE,UAAU;IAC3B,YAAY,EAAE,UAAU;IACxB,KAAK,EAAE,UAAU;IACjB,SAAS,EAAE,UAAU;IACrB,OAAO,EAAE,UAAU;IACnB,aAAa,EAAE,UAAU;IACzB,WAAW,EAAE,UAAU;IACvB,YAAY,EAAE,UAAU;IACxB,QAAQ,EAAE,UAAU;CACiD,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,aAAa,CAAC,KAAK,CAAC;QACzB,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/B,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,uCAAuC,EAAE,CAAC;AACtE,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,CACL,QAAQ,CAAC,KAAK,CAAC;QACf,uBAAuB,CAAC,KAAK,CAAC;QAC9B,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAClC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC;QACjC,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ;QACvC,iBAAiB,CAAC,KAAK,CAAC,eAAe,CAAC;QACxC,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5E,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;QAC5B,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC;QAChC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC;QAC/B,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,IAAI,sBAAsB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAClF,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,oBAAoB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC5E,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,8BAA8B,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxF,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,CAC9B,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,KAA8B;IAC7D,OAAO,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,KAAK,CAClD,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,UAAU,IAAI,GAAG,IAAI,KAAK,CACzD,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,CAAC;AACtE,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,CACL,QAAQ,CAAC,KAAK,CAAC;QACf,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC;QAC5B,OAAO,KAAK,CAAC,YAAY,CAAC,aAAa,KAAK,QAAQ;QACpD,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC;QACzC,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CACnC,CAAC;AACJ,CAAC","sourcesContent":["import { isComponentDataBindingRegistry } from './appManifest/bindings';\nimport { isDataSourceRegistry } from './appManifest/dataSources';\nimport { isGeneratedApiRegistry } from './appManifest/generatedApis';\nimport { isInfraManifest } from './appManifest/infra';\nimport {\n isManifestMetadata,\n isNavigatorSpec,\n isScreenRegistry,\n isSplashScreenSpec,\n isThemeConfig,\n} from './appManifest/screens';\nimport { isOptionalString, isRecord, isStringArray } from './appManifest/shared';\nimport type { AppManifest } from './types';\n\nexport type AppManifestParseResult =\n | { readonly ok: true; readonly manifest: AppManifest }\n | { readonly ok: false; readonly message: string };\n\nconst APP_MANIFEST_KEY_POLICY = {\n metadata: 'required',\n themes: 'required',\n activeThemeId: 'required',\n activeThemeMode: 'optional',\n splashScreen: 'optional',\n infra: 'required',\n navigator: 'required',\n screens: 'required',\n generatedApis: 'optional',\n dataSources: 'optional',\n dataBindings: 'optional',\n settings: 'required',\n} as const satisfies Record<keyof AppManifest, 'optional' | 'required'>;\n\n/**\n * Parse unknown JSON-compatible input at the canonical AppManifest boundary.\n *\n * Contracts owns structural manifest validation. Consumers may add semantic\n * diagnostics after this parser succeeds, but should not reconstruct the\n * AppManifest shape in their own packages.\n */\nexport function parseAppManifest(value: unknown): AppManifestParseResult {\n return isAppManifest(value)\n ? { ok: true, manifest: value }\n : { ok: false, message: 'Value is not a canonical AppManifest.' };\n}\n\n/** Return whether an unknown value satisfies the canonical AppManifest shape. */\nexport function isAppManifest(value: unknown): value is AppManifest {\n return (\n isRecord(value) &&\n hasRequiredManifestKeys(value) &&\n isManifestMetadata(value.metadata) &&\n Array.isArray(value.themes) &&\n value.themes.every(isThemeConfig) &&\n typeof value.activeThemeId === 'string' &&\n isActiveThemeMode(value.activeThemeMode) &&\n (value.splashScreen === undefined || isSplashScreenSpec(value.splashScreen)) &&\n isInfraManifest(value.infra) &&\n isNavigatorSpec(value.navigator) &&\n isScreenRegistry(value.screens) &&\n (value.generatedApis === undefined || isGeneratedApiRegistry(value.generatedApis)) &&\n (value.dataSources === undefined || isDataSourceRegistry(value.dataSources)) &&\n (value.dataBindings === undefined || isComponentDataBindingRegistry(value.dataBindings)) &&\n isAppSettings(value.settings)\n );\n}\n\nfunction hasRequiredManifestKeys(value: Record<string, unknown>): boolean {\n return Object.entries(APP_MANIFEST_KEY_POLICY).every(\n ([key, policy]) => policy === 'optional' || key in value,\n );\n}\n\nfunction isActiveThemeMode(value: unknown): boolean {\n return value === undefined || value === 'dark' || value === 'light';\n}\n\nfunction isAppSettings(value: unknown): boolean {\n return (\n isRecord(value) &&\n isRecord(value.localization) &&\n typeof value.localization.defaultLocale === 'string' &&\n isStringArray(value.localization.locales) &&\n isOptionalString(value.apiBaseUrl)\n );\n}\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC","sourcesContent":["export * from './auth';\nexport * from './bindings';\nexport * from './cli';\nexport * from './data';\nexport * from './db';\nexport * from './requirements';\nexport * from './runtimeCallbacks';\nexport * from './secretManifest';\nexport * from './secrets';\nexport * from './state';\nexport * from './storage';\nexport * from './theme';\nexport * from './types';\nexport * from './ui';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,MAAM,CAAC;AACrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC","sourcesContent":["export * from './appManifest';\nexport * from './auth';\nexport * from './bindings';\nexport * from './cli';\nexport * from './data';\nexport * from './db';\nexport * from './requirements';\nexport * from './runtimeCallbacks';\nexport * from './secretManifest';\nexport * from './secrets';\nexport * from './state';\nexport * from './storage';\nexport * from './theme';\nexport * from './types';\nexport * from './ui';\n"]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { isManifestValue, isOptionalString, isRecord } from './shared';
|
|
2
|
+
|
|
3
|
+
export function isComponentDataBindingRegistry(value: unknown): boolean {
|
|
4
|
+
return isRecord(value) && Object.values(value).every(isComponentDataBinding);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isBindingValueSource(value: unknown): boolean {
|
|
8
|
+
return (
|
|
9
|
+
isRecord(value) &&
|
|
10
|
+
typeof value.kind === 'string' &&
|
|
11
|
+
['context', 'event', 'literal', 'operation', 'state'].includes(value.kind) &&
|
|
12
|
+
(value.kind === 'literal'
|
|
13
|
+
? isManifestValue(value.value)
|
|
14
|
+
: value.kind === 'operation'
|
|
15
|
+
? isBindingOperationRef(value.operation) && isOptionalString(value.path)
|
|
16
|
+
: typeof value.path === 'string')
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isScreenDataLoaderDefinition(value: unknown): boolean {
|
|
21
|
+
return (
|
|
22
|
+
isRecord(value) &&
|
|
23
|
+
value.kind === 'operation' &&
|
|
24
|
+
isOptionalString(value.id) &&
|
|
25
|
+
isBindingOperationRef(value.operation) &&
|
|
26
|
+
(value.input === undefined || isBindingInputMap(value.input))
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isComponentDataBinding(value: unknown): boolean {
|
|
31
|
+
return (
|
|
32
|
+
isRecord(value) &&
|
|
33
|
+
typeof value.componentId === 'string' &&
|
|
34
|
+
isOptionalString(value.componentType) &&
|
|
35
|
+
(value.props === undefined ||
|
|
36
|
+
(isRecord(value.props) && Object.values(value.props).every(isPropBinding))) &&
|
|
37
|
+
(value.events === undefined ||
|
|
38
|
+
(isRecord(value.events) &&
|
|
39
|
+
Object.values(value.events).every(
|
|
40
|
+
(bindings) => Array.isArray(bindings) && bindings.every(isEventBinding),
|
|
41
|
+
)))
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isPropBinding(value: unknown): boolean {
|
|
46
|
+
return (
|
|
47
|
+
isRecord(value) &&
|
|
48
|
+
isBindingValueSource(value.source) &&
|
|
49
|
+
(value.fallback === undefined || isBindingFallback(value.fallback)) &&
|
|
50
|
+
(value.loading === undefined || isBindingLifecycleBehavior(value.loading)) &&
|
|
51
|
+
(value.error === undefined || isBindingLifecycleBehavior(value.error)) &&
|
|
52
|
+
(value.empty === undefined || isBindingLifecycleBehavior(value.empty)) &&
|
|
53
|
+
isOptionalBindingTransforms(value.transforms)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isEventBinding(value: unknown): boolean {
|
|
58
|
+
return (
|
|
59
|
+
isRecord(value) &&
|
|
60
|
+
isEventBindingTarget(value.target) &&
|
|
61
|
+
(value.input === undefined || isBindingInputMap(value.input)) &&
|
|
62
|
+
(value.when === undefined || isBindingCondition(value.when))
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isEventBindingTarget(value: unknown): boolean {
|
|
67
|
+
return (
|
|
68
|
+
isRecord(value) &&
|
|
69
|
+
((value.kind === 'action' && typeof value.type === 'string') ||
|
|
70
|
+
(value.kind === 'operation' && isBindingOperationRef(value.operation)))
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isBindingCondition(value: unknown): boolean {
|
|
75
|
+
return (
|
|
76
|
+
isRecord(value) &&
|
|
77
|
+
isBindingValueSource(value.source) &&
|
|
78
|
+
['eq', 'exists', 'neq', 'notExists'].includes(String(value.operator)) &&
|
|
79
|
+
(value.value === undefined || isManifestValue(value.value))
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isBindingOperationRef(value: unknown): boolean {
|
|
84
|
+
return (
|
|
85
|
+
isRecord(value) &&
|
|
86
|
+
typeof value.dataSourceId === 'string' &&
|
|
87
|
+
typeof value.operationId === 'string' &&
|
|
88
|
+
isOptionalString(value.endpointId)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isBindingFallback(value: unknown): boolean {
|
|
93
|
+
return (
|
|
94
|
+
isRecord(value) &&
|
|
95
|
+
(value.value === undefined || isManifestValue(value.value)) &&
|
|
96
|
+
(value.source === undefined || isBindingValueSource(value.source))
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function isBindingLifecycleBehavior(value: unknown): boolean {
|
|
101
|
+
return (
|
|
102
|
+
isRecord(value) &&
|
|
103
|
+
typeof value.state === 'string' &&
|
|
104
|
+
['empty', 'error', 'loading'].includes(value.state) &&
|
|
105
|
+
(value.fallback === undefined || isBindingFallback(value.fallback)) &&
|
|
106
|
+
isOptionalString(value.message)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function isOptionalBindingTransforms(value: unknown): boolean {
|
|
111
|
+
return (
|
|
112
|
+
value === undefined ||
|
|
113
|
+
(Array.isArray(value) &&
|
|
114
|
+
value.every((transform) => ['lowercase', 'trim', 'uppercase'].includes(String(transform))))
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isBindingInputMap(value: unknown): boolean {
|
|
119
|
+
return isRecord(value) && Object.values(value).every(isBindingInputValue);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isBindingInputValue(value: unknown): boolean {
|
|
123
|
+
return (
|
|
124
|
+
isRecord(value) &&
|
|
125
|
+
typeof value.kind === 'string' &&
|
|
126
|
+
((value.kind === 'array' &&
|
|
127
|
+
Array.isArray(value.items) &&
|
|
128
|
+
value.items.every(isBindingInputValue)) ||
|
|
129
|
+
(value.kind === 'literal' && isManifestValue(value.value)) ||
|
|
130
|
+
(value.kind === 'object' && isBindingInputMap(value.fields)) ||
|
|
131
|
+
(value.kind === 'source' &&
|
|
132
|
+
isBindingValueSource(value.source) &&
|
|
133
|
+
isOptionalBindingTransforms(value.transforms)))
|
|
134
|
+
);
|
|
135
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { isManifestValue, isOptionalBoolean, isOptionalString, isRecord } from './shared';
|
|
2
|
+
|
|
3
|
+
export function isDataSourceRegistry(value: unknown): boolean {
|
|
4
|
+
return isRecord(value) && Object.values(value).every(isDataSourceConfig);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function isDataSourceConfig(value: unknown): boolean {
|
|
8
|
+
if (!hasBaseDataSourceShape(value)) return false;
|
|
9
|
+
if (value.kind === 'database') return isDatabaseDataSource(value);
|
|
10
|
+
if (value.origin === 'generated') return isGeneratedDataSource(value);
|
|
11
|
+
if (value.origin !== 'external') return false;
|
|
12
|
+
return isExternalDataSource(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function hasBaseDataSourceShape(value: unknown): value is Record<string, unknown> {
|
|
16
|
+
return (
|
|
17
|
+
isRecord(value) &&
|
|
18
|
+
typeof value.id === 'string' &&
|
|
19
|
+
(value.kind === 'api' || value.kind === 'database') &&
|
|
20
|
+
isOptionalString(value.name) &&
|
|
21
|
+
isOptionalString(value.description) &&
|
|
22
|
+
(value.credential === undefined || isCredentialRef(value.credential)) &&
|
|
23
|
+
isDataEndpointRegistry(value.endpoints) &&
|
|
24
|
+
(value.schemas === undefined || isRecord(value.schemas)) &&
|
|
25
|
+
(value.metadata === undefined || isManifestValue(value.metadata))
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isDatabaseDataSource(value: Record<string, unknown>): boolean {
|
|
30
|
+
return (
|
|
31
|
+
isRecord(value.adapter) && value.adapter.kind === 'database' && isAdapterRef(value.adapter)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isGeneratedDataSource(value: Record<string, unknown>): boolean {
|
|
36
|
+
return (
|
|
37
|
+
value.protocol === 'rest' &&
|
|
38
|
+
typeof value.generatedApiId === 'string' &&
|
|
39
|
+
isRecord(value.adapter) &&
|
|
40
|
+
value.adapter.kind === 'database' &&
|
|
41
|
+
isAdapterRef(value.adapter)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isExternalDataSource(value: Record<string, unknown>): boolean {
|
|
46
|
+
if (value.protocol === 'rest') {
|
|
47
|
+
return (
|
|
48
|
+
typeof value.baseUrl === 'string' &&
|
|
49
|
+
(value.openApi === undefined || isOpenApiDocumentRef(value.openApi))
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (value.protocol === 'graphql') {
|
|
54
|
+
return (
|
|
55
|
+
typeof value.endpointUrl === 'string' &&
|
|
56
|
+
(value.introspection === undefined || isGraphQlIntrospection(value.introspection))
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isOpenApiDocumentRef(value: unknown): boolean {
|
|
64
|
+
return (
|
|
65
|
+
isRecord(value) &&
|
|
66
|
+
isOptionalString(value.url) &&
|
|
67
|
+
isOptionalString(value.documentId) &&
|
|
68
|
+
isOptionalString(value.version)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isGraphQlIntrospection(value: unknown): boolean {
|
|
73
|
+
return (
|
|
74
|
+
isRecord(value) && typeof value.enabled === 'boolean' && isOptionalString(value.schemaVersion)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isDataEndpointRegistry(value: unknown): boolean {
|
|
79
|
+
return isRecord(value) && Object.values(value).every(isDataEndpointConfig);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isDataEndpointConfig(value: unknown): boolean {
|
|
83
|
+
return (
|
|
84
|
+
isRecord(value) &&
|
|
85
|
+
typeof value.id === 'string' &&
|
|
86
|
+
typeof value.kind === 'string' &&
|
|
87
|
+
isOptionalString(value.name) &&
|
|
88
|
+
isOptionalString(value.description) &&
|
|
89
|
+
isOptionalString(value.baseUrl) &&
|
|
90
|
+
isOptionalString(value.path) &&
|
|
91
|
+
(value.credential === undefined || isCredentialRef(value.credential)) &&
|
|
92
|
+
isRecord(value.operations) &&
|
|
93
|
+
Object.values(value.operations).every(isDataOperationConfig) &&
|
|
94
|
+
(value.metadata === undefined || isManifestValue(value.metadata))
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function isDataOperationConfig(value: unknown): boolean {
|
|
99
|
+
return (
|
|
100
|
+
isRecord(value) &&
|
|
101
|
+
typeof value.id === 'string' &&
|
|
102
|
+
isOptionalString(value.endpointId) &&
|
|
103
|
+
isOptionalString(value.name) &&
|
|
104
|
+
isOptionalString(value.description) &&
|
|
105
|
+
typeof value.protocol === 'string' &&
|
|
106
|
+
typeof value.intent === 'string' &&
|
|
107
|
+
['action', 'create', 'delete', 'read', 'update'].includes(value.intent) &&
|
|
108
|
+
isOptionalString(value.method) &&
|
|
109
|
+
isOptionalString(value.path) &&
|
|
110
|
+
(value.request === undefined || isDataOperationRequest(value.request)) &&
|
|
111
|
+
(value.response === undefined || isDataOperationResponse(value.response)) &&
|
|
112
|
+
(value.pagination === undefined || isRecord(value.pagination)) &&
|
|
113
|
+
(value.credential === undefined || isCredentialRef(value.credential)) &&
|
|
114
|
+
(value.metadata === undefined || isManifestValue(value.metadata))
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isDataOperationRequest(value: unknown): boolean {
|
|
119
|
+
return (
|
|
120
|
+
isRecord(value) &&
|
|
121
|
+
isDataSchemaSlot(value) &&
|
|
122
|
+
(value.parameters === undefined ||
|
|
123
|
+
(Array.isArray(value.parameters) && value.parameters.every(isDataOperationParameter)))
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function isDataOperationParameter(value: unknown): boolean {
|
|
128
|
+
return (
|
|
129
|
+
isRecord(value) &&
|
|
130
|
+
isDataSchemaSlot(value) &&
|
|
131
|
+
typeof value.name === 'string' &&
|
|
132
|
+
typeof value.location === 'string' &&
|
|
133
|
+
['body', 'cookie', 'header', 'path', 'query'].includes(value.location) &&
|
|
134
|
+
isOptionalBoolean(value.required) &&
|
|
135
|
+
isOptionalString(value.description) &&
|
|
136
|
+
(value.default === undefined || isManifestValue(value.default))
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function isDataOperationResponse(value: unknown): boolean {
|
|
141
|
+
return (
|
|
142
|
+
isRecord(value) &&
|
|
143
|
+
isDataSchemaSlot(value) &&
|
|
144
|
+
(value.status === undefined ||
|
|
145
|
+
typeof value.status === 'string' ||
|
|
146
|
+
typeof value.status === 'number') &&
|
|
147
|
+
isOptionalString(value.contentType) &&
|
|
148
|
+
isOptionalString(value.description)
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isDataSchemaSlot(value: unknown): boolean {
|
|
153
|
+
return isRecord(value) && (value.schema === undefined || isRecord(value.schema));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function isCredentialRef(value: unknown): boolean {
|
|
157
|
+
return (
|
|
158
|
+
isRecord(value) &&
|
|
159
|
+
typeof value.id === 'string' &&
|
|
160
|
+
typeof value.kind === 'string' &&
|
|
161
|
+
isOptionalString(value.label) &&
|
|
162
|
+
isOptionalString(value.scope)
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function isAdapterRef(value: unknown): boolean {
|
|
167
|
+
return (
|
|
168
|
+
isRecord(value) &&
|
|
169
|
+
typeof value.id === 'string' &&
|
|
170
|
+
typeof value.kind === 'string' &&
|
|
171
|
+
isOptionalString(value.packageName) &&
|
|
172
|
+
isOptionalString(value.exportName) &&
|
|
173
|
+
(value.config === undefined || isManifestValue(value.config))
|
|
174
|
+
);
|
|
175
|
+
}
|