@quazardous/qdadm 1.19.3
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/LICENSE +21 -0
- package/README.md +111 -0
- package/package.json +101 -0
- package/src/assets/logo.svg +6 -0
- package/src/auth/SessionAuthAdapter.ts +459 -0
- package/src/auth/index.ts +15 -0
- package/src/chain/ActiveStack.ts +154 -0
- package/src/chain/StackHydrator.ts +292 -0
- package/src/chain/index.ts +25 -0
- package/src/chain/useActiveStack.ts +120 -0
- package/src/chain/useStackHydrator.ts +155 -0
- package/src/components/BoolCell.vue +34 -0
- package/src/components/InfoBanner.vue +73 -0
- package/src/components/QdadmRoot.vue +52 -0
- package/src/components/SeverityTag.vue +86 -0
- package/src/components/dialogs/BulkStatusDialog.vue +60 -0
- package/src/components/dialogs/MultiStepDialog.vue +331 -0
- package/src/components/dialogs/SimpleDialog.vue +122 -0
- package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
- package/src/components/display/BannerZone.vue +65 -0
- package/src/components/display/CardsGrid.vue +72 -0
- package/src/components/display/CopyableId.vue +84 -0
- package/src/components/display/EmptyState.vue +62 -0
- package/src/components/display/IntensityBar.vue +190 -0
- package/src/components/display/RichCardsGrid.vue +101 -0
- package/src/components/edit/FormActions.vue +78 -0
- package/src/components/edit/FormField.vue +82 -0
- package/src/components/edit/FormInput.vue +158 -0
- package/src/components/edit/FormPage.vue +260 -0
- package/src/components/edit/FormTab.vue +217 -0
- package/src/components/edit/FormTabs.vue +120 -0
- package/src/components/edit/LookupField.vue +406 -0
- package/src/components/edit/LookupPickerDialog.vue +230 -0
- package/src/components/editors/JsonEditorFoldable.vue +470 -0
- package/src/components/editors/JsonStructuredField.vue +264 -0
- package/src/components/editors/JsonViewer.vue +51 -0
- package/src/components/editors/KeyValueEditor.vue +314 -0
- package/src/components/editors/LanguageEditor.vue +259 -0
- package/src/components/editors/PermissionEditor.vue +558 -0
- package/src/components/editors/ScopeEditor.vue +372 -0
- package/src/components/editors/VanillaJsonEditor.vue +183 -0
- package/src/components/index.ts +83 -0
- package/src/components/item/FieldGroups.vue +392 -0
- package/src/components/layout/AppLayout.vue +1032 -0
- package/src/components/layout/BaseLayout.vue +190 -0
- package/src/components/layout/Breadcrumb.vue +55 -0
- package/src/components/layout/DashboardLayout.vue +104 -0
- package/src/components/layout/FormLayout.vue +256 -0
- package/src/components/layout/ListLayout.vue +278 -0
- package/src/components/layout/PageHeader.vue +156 -0
- package/src/components/layout/PageLayout.vue +126 -0
- package/src/components/layout/PageNav.vue +192 -0
- package/src/components/layout/SidebarBox.vue +87 -0
- package/src/components/layout/Zone.vue +182 -0
- package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
- package/src/components/layout/defaults/DefaultFooter.vue +89 -0
- package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
- package/src/components/layout/defaults/DefaultHeader.vue +78 -0
- package/src/components/layout/defaults/DefaultMenu.vue +188 -0
- package/src/components/layout/defaults/DefaultPagination.vue +75 -0
- package/src/components/layout/defaults/DefaultTable.vue +137 -0
- package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
- package/src/components/layout/defaults/index.ts +16 -0
- package/src/components/lists/ActionButtons.vue +49 -0
- package/src/components/lists/ActionColumn.vue +40 -0
- package/src/components/lists/FilterBar.vue +54 -0
- package/src/components/lists/ListPage.vue +467 -0
- package/src/components/pages/LoginPage.vue +334 -0
- package/src/components/pages/NotFoundPage.vue +98 -0
- package/src/components/show/ShowDisplay.vue +343 -0
- package/src/components/show/ShowField.vue +67 -0
- package/src/components/show/ShowPage.vue +431 -0
- package/src/composables/index.ts +155 -0
- package/src/composables/useApp.ts +67 -0
- package/src/composables/useAuth.ts +98 -0
- package/src/composables/useBareForm.ts +319 -0
- package/src/composables/useBreadcrumb.ts +252 -0
- package/src/composables/useChildPage.ts +113 -0
- package/src/composables/useCurrentEntity.ts +60 -0
- package/src/composables/useDeferred.ts +94 -0
- package/src/composables/useDirtyState.ts +138 -0
- package/src/composables/useEntityItemFormPage.ts +942 -0
- package/src/composables/useEntityItemFormPage.types.ts +451 -0
- package/src/composables/useEntityItemPage.ts +438 -0
- package/src/composables/useEntityItemShowPage.ts +722 -0
- package/src/composables/useFieldManager.ts +692 -0
- package/src/composables/useForm.ts +544 -0
- package/src/composables/useGuardStore.ts +53 -0
- package/src/composables/useHooks.ts +56 -0
- package/src/composables/useInfoBanner.ts +217 -0
- package/src/composables/useJsonSyntax.ts +122 -0
- package/src/composables/useLayoutResolver.ts +329 -0
- package/src/composables/useListPage.ts +1535 -0
- package/src/composables/useListPage.types.ts +437 -0
- package/src/composables/useListPage.utils.ts +101 -0
- package/src/composables/useNavContext.ts +439 -0
- package/src/composables/useNavigation.ts +216 -0
- package/src/composables/useOptionsLookup.ts +323 -0
- package/src/composables/usePageTitle.ts +84 -0
- package/src/composables/useSSEBridge.ts +142 -0
- package/src/composables/useSemanticBreadcrumb.ts +222 -0
- package/src/composables/useSidebarState.ts +24 -0
- package/src/composables/useSignals.ts +52 -0
- package/src/composables/useUnsavedChangesGuard.ts +155 -0
- package/src/composables/useUserImpersonator.ts +317 -0
- package/src/composables/useZoneRegistry.ts +252 -0
- package/src/core/bundles.ts +558 -0
- package/src/core/decorator.ts +420 -0
- package/src/core/extension.ts +470 -0
- package/src/core/index.ts +59 -0
- package/src/deferred/DeferredRegistry.ts +353 -0
- package/src/deferred/index.ts +15 -0
- package/src/editors/index.ts +12 -0
- package/src/entity/EntityManager.cache.ts +530 -0
- package/src/entity/EntityManager.crud.ts +615 -0
- package/src/entity/EntityManager.interface.ts +78 -0
- package/src/entity/EntityManager.query.ts +221 -0
- package/src/entity/EntityManager.relations.ts +151 -0
- package/src/entity/EntityManager.ts +944 -0
- package/src/entity/EntityManager.types.ts +288 -0
- package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
- package/src/entity/auth/EntityAuthAdapter.ts +119 -0
- package/src/entity/auth/PermissiveAdapter.ts +43 -0
- package/src/entity/auth/RoleHierarchy.ts +128 -0
- package/src/entity/auth/SecurityChecker.ts +202 -0
- package/src/entity/auth/factory.ts +203 -0
- package/src/entity/auth/index.ts +47 -0
- package/src/entity/factory.test.js +189 -0
- package/src/entity/factory.ts +146 -0
- package/src/entity/index.ts +49 -0
- package/src/entity/storage/ApiStorage.ts +228 -0
- package/src/entity/storage/IStorage.ts +100 -0
- package/src/entity/storage/LocalStorage.ts +200 -0
- package/src/entity/storage/MemoryStorage.ts +184 -0
- package/src/entity/storage/MockApiStorage.ts +318 -0
- package/src/entity/storage/SdkStorage.ts +377 -0
- package/src/entity/storage/factory.test.js +159 -0
- package/src/entity/storage/factory.ts +209 -0
- package/src/entity/storage/index.ts +75 -0
- package/src/gen/FieldMapper.ts +122 -0
- package/src/gen/StorageProfileFactory.ts +93 -0
- package/src/gen/connectors/BaseConnector.ts +150 -0
- package/src/gen/connectors/ManualConnector.test.js +499 -0
- package/src/gen/connectors/ManualConnector.ts +414 -0
- package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
- package/src/gen/connectors/OpenAPIConnector.ts +693 -0
- package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
- package/src/gen/connectors/index.ts +27 -0
- package/src/gen/createManagers.ts +245 -0
- package/src/gen/decorators.ts +134 -0
- package/src/gen/generateManagers.test.js +540 -0
- package/src/gen/generateManagers.ts +398 -0
- package/src/gen/index.ts +66 -0
- package/src/gen/schema.ts +248 -0
- package/src/gen/vite-plugin.ts +114 -0
- package/src/generated/managers/testManager.js +45 -0
- package/src/generated/managers/testManager.ts +46 -0
- package/src/hooks/HookRegistry.ts +16 -0
- package/src/hooks/index.ts +15 -0
- package/src/i18n/I18n.ts +344 -0
- package/src/i18n/IncrementalDomainProvider.ts +153 -0
- package/src/i18n/InlineTranslationProvider.ts +4 -0
- package/src/i18n/LazyTranslationProvider.ts +102 -0
- package/src/i18n/MessagesRegistry.ts +4 -0
- package/src/i18n/Resolver.ts +4 -0
- package/src/i18n/__tests__/I18n.test.ts +169 -0
- package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
- package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
- package/src/i18n/__tests__/Resolver.test.ts +271 -0
- package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
- package/src/i18n/defaults/core.en.yml +55 -0
- package/src/i18n/defaults/core.fr.yml +55 -0
- package/src/i18n/index.ts +55 -0
- package/src/i18n/loaders/raw-modules.d.ts +15 -0
- package/src/i18n/loaders/yaml.ts +35 -0
- package/src/i18n/strategies.ts +4 -0
- package/src/i18n/types.ts +34 -0
- package/src/i18n/useI18n.ts +34 -0
- package/src/index.ts +453 -0
- package/src/kernel/EventRouter.ts +23 -0
- package/src/kernel/Kernel.api.ts +79 -0
- package/src/kernel/Kernel.auth.ts +120 -0
- package/src/kernel/Kernel.i18n.ts +29 -0
- package/src/kernel/Kernel.modules.ts +170 -0
- package/src/kernel/Kernel.registries.ts +237 -0
- package/src/kernel/Kernel.routing.ts +334 -0
- package/src/kernel/Kernel.ts +460 -0
- package/src/kernel/Kernel.types.ts +263 -0
- package/src/kernel/Kernel.vue.ts +304 -0
- package/src/kernel/KernelContext.entities.ts +80 -0
- package/src/kernel/KernelContext.events.ts +57 -0
- package/src/kernel/KernelContext.i18n.ts +37 -0
- package/src/kernel/KernelContext.permissions.ts +38 -0
- package/src/kernel/KernelContext.routing.ts +280 -0
- package/src/kernel/KernelContext.ts +252 -0
- package/src/kernel/KernelContext.types.ts +173 -0
- package/src/kernel/KernelContext.zones.ts +54 -0
- package/src/kernel/Module.ts +169 -0
- package/src/kernel/ModuleLoader.ts +645 -0
- package/src/kernel/SSEBridge.ts +11 -0
- package/src/kernel/SignalBus.ts +48 -0
- package/src/kernel/index.ts +56 -0
- package/src/module/index.ts +33 -0
- package/src/module/moduleRegistry.ts +492 -0
- package/src/modules/debug/AuthCollector.ts +501 -0
- package/src/modules/debug/Collector.ts +20 -0
- package/src/modules/debug/DebugBridge.ts +14 -0
- package/src/modules/debug/DebugModule.ts +220 -0
- package/src/modules/debug/EntitiesCollector.ts +839 -0
- package/src/modules/debug/ErrorCollector.ts +4 -0
- package/src/modules/debug/I18nCollector.ts +9 -0
- package/src/modules/debug/LocalStorageAdapter.ts +7 -0
- package/src/modules/debug/RouterCollector.ts +449 -0
- package/src/modules/debug/SignalCollector.ts +4 -0
- package/src/modules/debug/ToastCollector.ts +4 -0
- package/src/modules/debug/ZonesCollector.ts +447 -0
- package/src/modules/debug/components/DebugBar.vue +31 -0
- package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
- package/src/modules/debug/components/index.ts +9 -0
- package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
- package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
- package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
- package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
- package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
- package/src/modules/debug/components/panels/index.ts +16 -0
- package/src/modules/debug/index.ts +58 -0
- package/src/modules/debug/styles.scss +2671 -0
- package/src/notifications/NotificationBadge.vue +35 -0
- package/src/notifications/NotificationListener.vue +71 -0
- package/src/notifications/NotificationModule.ts +76 -0
- package/src/notifications/NotificationPanel.vue +478 -0
- package/src/notifications/NotificationStore.ts +288 -0
- package/src/notifications/index.ts +42 -0
- package/src/notifications/styles.scss +32 -0
- package/src/orchestrator/Orchestrator.ts +427 -0
- package/src/orchestrator/index.ts +8 -0
- package/src/orchestrator/useOrchestrator.ts +80 -0
- package/src/plugin.ts +251 -0
- package/src/query/FilterQuery.ts +306 -0
- package/src/query/QueryExecutor.ts +341 -0
- package/src/query/index.ts +16 -0
- package/src/security/EntityRolesProvider.ts +385 -0
- package/src/security/PermissionMatcher.ts +152 -0
- package/src/security/PermissionRegistry.ts +273 -0
- package/src/security/PersistableRolesProvider.ts +584 -0
- package/src/security/RolesManager.ts +136 -0
- package/src/security/RolesProvider.ts +167 -0
- package/src/security/RolesProviderStorage.ts +211 -0
- package/src/security/SecurityModule.ts +94 -0
- package/src/security/StaticRolesProvider.ts +117 -0
- package/src/security/UsersManager.ts +163 -0
- package/src/security/index.ts +77 -0
- package/src/security/pages/RoleForm.vue +276 -0
- package/src/security/pages/RoleList.vue +123 -0
- package/src/styles/_alerts.scss +95 -0
- package/src/styles/_buttons.scss +391 -0
- package/src/styles/_cards.scss +241 -0
- package/src/styles/_code.scss +78 -0
- package/src/styles/_dialogs.scss +55 -0
- package/src/styles/_filter-bar.scss +70 -0
- package/src/styles/_forms.scss +434 -0
- package/src/styles/_helpers.scss +153 -0
- package/src/styles/_lists.scss +225 -0
- package/src/styles/_main.scss +356 -0
- package/src/styles/_markdown.scss +88 -0
- package/src/styles/_responsive.scss +255 -0
- package/src/styles/_show-pages.scss +186 -0
- package/src/styles/_sidebar.scss +380 -0
- package/src/styles/_states.scss +115 -0
- package/src/styles/_stats.scss +47 -0
- package/src/styles/_variables.scss +224 -0
- package/src/styles/index.scss +38 -0
- package/src/styles/theme/_components.scss +331 -0
- package/src/styles/theme/_index.scss +10 -0
- package/src/styles/theme/_tokens.scss +147 -0
- package/src/styles/theme/_utilities.scss +175 -0
- package/src/toast/ToastBridgeModule.ts +68 -0
- package/src/toast/ToastListener.vue +55 -0
- package/src/toast/index.ts +26 -0
- package/src/toast/useSignalToast.ts +154 -0
- package/src/types/index.ts +285 -0
- package/src/types/pluralize.d.ts +19 -0
- package/src/types/quarkernel.d.ts +50 -0
- package/src/utils/formatters.ts +174 -0
- package/src/utils/index.ts +35 -0
- package/src/utils/transformers.ts +131 -0
- package/src/vite/qdadmDebugPlugin.ts +401 -0
- package/src/vite-env.d.ts +50 -0
- package/src/zones/ZoneRegistry.ts +934 -0
- package/src/zones/index.ts +29 -0
- package/src/zones/zones.ts +191 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual Connector
|
|
3
|
+
*
|
|
4
|
+
* Parses inline entity/field definitions into UnifiedEntitySchema format.
|
|
5
|
+
* Used when schemas are defined directly in configuration rather than
|
|
6
|
+
* extracted from OpenAPI specs or other sources.
|
|
7
|
+
*
|
|
8
|
+
* @module gen/connectors/ManualConnector
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BaseConnector, type ConnectorOptions, type ParseResult, type ParseWarning } from './BaseConnector'
|
|
12
|
+
import {
|
|
13
|
+
UNIFIED_FIELD_TYPES,
|
|
14
|
+
isValidFieldType,
|
|
15
|
+
type UnifiedEntitySchema,
|
|
16
|
+
type UnifiedFieldSchema,
|
|
17
|
+
type UnifiedFieldReference,
|
|
18
|
+
type UnifiedFieldType,
|
|
19
|
+
} from '../schema'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Manual field definition input
|
|
23
|
+
*/
|
|
24
|
+
export interface ManualFieldInput {
|
|
25
|
+
/** Field name (required) */
|
|
26
|
+
name: string
|
|
27
|
+
/** Field type (required, must be valid UnifiedFieldType) */
|
|
28
|
+
type: string
|
|
29
|
+
/** Human-readable label */
|
|
30
|
+
label?: string
|
|
31
|
+
/** Whether field is required */
|
|
32
|
+
required?: boolean
|
|
33
|
+
/** Whether field is read-only */
|
|
34
|
+
readOnly?: boolean
|
|
35
|
+
/** Whether field should be hidden in UI */
|
|
36
|
+
hidden?: boolean
|
|
37
|
+
/** Original format hint */
|
|
38
|
+
format?: string
|
|
39
|
+
/** Allowed values for enumeration */
|
|
40
|
+
enum?: string[]
|
|
41
|
+
/** Default value */
|
|
42
|
+
default?: unknown
|
|
43
|
+
/** Relation to another entity */
|
|
44
|
+
reference?: UnifiedFieldReference
|
|
45
|
+
/** Project-specific extensions */
|
|
46
|
+
extensions?: Record<string, unknown>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Manual entity definition input
|
|
51
|
+
*/
|
|
52
|
+
export interface ManualEntityInput {
|
|
53
|
+
/** Entity name (required) */
|
|
54
|
+
name: string
|
|
55
|
+
/** API endpoint path (required) */
|
|
56
|
+
endpoint: string
|
|
57
|
+
/** Human-readable singular label */
|
|
58
|
+
label?: string
|
|
59
|
+
/** Human-readable plural label */
|
|
60
|
+
labelPlural?: string
|
|
61
|
+
/** Field used as display label */
|
|
62
|
+
labelField?: string
|
|
63
|
+
/** Route prefix for admin UI */
|
|
64
|
+
routePrefix?: string
|
|
65
|
+
/** Primary key field name */
|
|
66
|
+
idField?: string
|
|
67
|
+
/** Whether entity is read-only */
|
|
68
|
+
readOnly?: boolean
|
|
69
|
+
/** Field definitions */
|
|
70
|
+
fields?: Record<string, ManualFieldInput>
|
|
71
|
+
/** Project-specific extensions */
|
|
72
|
+
extensions?: Record<string, unknown>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Manual source input - array of entities or single entity
|
|
77
|
+
*/
|
|
78
|
+
export type ManualSourceInput =
|
|
79
|
+
| ManualEntityInput[]
|
|
80
|
+
| ManualEntityInput
|
|
81
|
+
| { entities: ManualEntityInput[] }
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Manual Connector for parsing inline entity/field definitions.
|
|
85
|
+
*
|
|
86
|
+
* Accepts entity definitions in various formats:
|
|
87
|
+
* - Single entity object
|
|
88
|
+
* - Array of entity objects
|
|
89
|
+
* - Object with `entities` array
|
|
90
|
+
*
|
|
91
|
+
* @extends BaseConnector
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // Parse a single entity
|
|
95
|
+
* const connector = new ManualConnector()
|
|
96
|
+
* const schemas = connector.parse({
|
|
97
|
+
* name: 'users',
|
|
98
|
+
* endpoint: '/api/users',
|
|
99
|
+
* fields: {
|
|
100
|
+
* id: { name: 'id', type: 'number', readOnly: true },
|
|
101
|
+
* email: { name: 'email', type: 'email', required: true }
|
|
102
|
+
* }
|
|
103
|
+
* })
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // Parse multiple entities
|
|
107
|
+
* const schemas = connector.parse([
|
|
108
|
+
* { name: 'users', endpoint: '/api/users', fields: { ... } },
|
|
109
|
+
* { name: 'posts', endpoint: '/api/posts', fields: { ... } }
|
|
110
|
+
* ])
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* // Strict mode throws on validation errors
|
|
114
|
+
* const connector = new ManualConnector({ strict: true })
|
|
115
|
+
* connector.parse({ name: 'users' }) // throws: missing 'endpoint'
|
|
116
|
+
*/
|
|
117
|
+
export class ManualConnector extends BaseConnector {
|
|
118
|
+
constructor(options: ConnectorOptions = {}) {
|
|
119
|
+
super(options)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Parse manual entity definitions into UnifiedEntitySchema format
|
|
124
|
+
*
|
|
125
|
+
* @param source - Manual entity definitions
|
|
126
|
+
* @returns Parsed entity schemas
|
|
127
|
+
* @throws If validation fails (always in strict mode, on critical errors otherwise)
|
|
128
|
+
*/
|
|
129
|
+
parse(source: ManualSourceInput): UnifiedEntitySchema[] {
|
|
130
|
+
const entities = this._normalizeSource(source)
|
|
131
|
+
const results: UnifiedEntitySchema[] = []
|
|
132
|
+
|
|
133
|
+
for (const entity of entities) {
|
|
134
|
+
const validated = this._validateEntity(entity)
|
|
135
|
+
if (validated) {
|
|
136
|
+
results.push(this._transformEntity(validated))
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return results
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Parse with detailed result including warnings
|
|
145
|
+
*
|
|
146
|
+
* @param source - Manual entity definitions
|
|
147
|
+
* @returns Schemas and warnings
|
|
148
|
+
*/
|
|
149
|
+
parseWithWarnings(source: ManualSourceInput): ParseResult {
|
|
150
|
+
const warnings: ParseWarning[] = []
|
|
151
|
+
const entities = this._normalizeSource(source)
|
|
152
|
+
const results: UnifiedEntitySchema[] = []
|
|
153
|
+
|
|
154
|
+
for (const entity of entities) {
|
|
155
|
+
const entityWarnings = this._collectWarnings(entity)
|
|
156
|
+
warnings.push(...entityWarnings)
|
|
157
|
+
|
|
158
|
+
const validated = this._validateEntity(entity)
|
|
159
|
+
if (validated) {
|
|
160
|
+
results.push(this._transformEntity(validated))
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return { schemas: results, warnings }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Normalize various source formats into entity array
|
|
169
|
+
*
|
|
170
|
+
* @private
|
|
171
|
+
* @param source - Source in any supported format
|
|
172
|
+
* @returns Normalized entity array
|
|
173
|
+
*/
|
|
174
|
+
private _normalizeSource(source: ManualSourceInput): ManualEntityInput[] {
|
|
175
|
+
if (!source) {
|
|
176
|
+
return []
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Array of entities
|
|
180
|
+
if (Array.isArray(source)) {
|
|
181
|
+
return source
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Object with entities array
|
|
185
|
+
if ('entities' in source && Array.isArray(source.entities)) {
|
|
186
|
+
return source.entities
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Single entity object (may be missing name - validation will catch it)
|
|
190
|
+
if (typeof source === 'object') {
|
|
191
|
+
return [source as ManualEntityInput]
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return []
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Validate entity definition
|
|
199
|
+
*
|
|
200
|
+
* @private
|
|
201
|
+
* @param entity - Entity to validate
|
|
202
|
+
* @returns Validated entity or null if invalid
|
|
203
|
+
* @throws In strict mode, throws on validation error
|
|
204
|
+
*/
|
|
205
|
+
private _validateEntity(entity: ManualEntityInput): ManualEntityInput | null {
|
|
206
|
+
const entityName = entity.name || '(unnamed)'
|
|
207
|
+
|
|
208
|
+
// Validate entity.name
|
|
209
|
+
if (!entity.name || typeof entity.name !== 'string' || entity.name.trim() === '') {
|
|
210
|
+
const message = `ManualConnector: entity ${entityName} missing required field 'name'`
|
|
211
|
+
if (this.strict) {
|
|
212
|
+
throw new Error(message)
|
|
213
|
+
}
|
|
214
|
+
return null
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Validate entity.endpoint
|
|
218
|
+
if (!entity.endpoint || typeof entity.endpoint !== 'string' || entity.endpoint.trim() === '') {
|
|
219
|
+
const message = `ManualConnector: entity '${entity.name}' missing required field 'endpoint'`
|
|
220
|
+
if (this.strict) {
|
|
221
|
+
throw new Error(message)
|
|
222
|
+
}
|
|
223
|
+
return null
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Validate fields if present
|
|
227
|
+
if (entity.fields) {
|
|
228
|
+
for (const [fieldKey, field] of Object.entries(entity.fields)) {
|
|
229
|
+
if (!this._validateField(entity.name, fieldKey, field)) {
|
|
230
|
+
if (this.strict) {
|
|
231
|
+
// Error already thrown in strict mode by _validateField
|
|
232
|
+
return null
|
|
233
|
+
}
|
|
234
|
+
// In non-strict mode, skip invalid fields by not adding them
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return entity
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Validate field definition
|
|
244
|
+
*
|
|
245
|
+
* @private
|
|
246
|
+
* @param entityName - Parent entity name for error context
|
|
247
|
+
* @param fieldKey - Field key in fields object
|
|
248
|
+
* @param field - Field to validate
|
|
249
|
+
* @returns True if valid
|
|
250
|
+
* @throws In strict mode, throws on validation error
|
|
251
|
+
*/
|
|
252
|
+
private _validateField(entityName: string, fieldKey: string, field: ManualFieldInput): boolean {
|
|
253
|
+
// Validate field.name
|
|
254
|
+
if (!field.name || typeof field.name !== 'string' || field.name.trim() === '') {
|
|
255
|
+
const message = `ManualConnector: entity '${entityName}' field '${fieldKey}' missing required property 'name'`
|
|
256
|
+
if (this.strict) {
|
|
257
|
+
throw new Error(message)
|
|
258
|
+
}
|
|
259
|
+
return false
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Validate field.type exists
|
|
263
|
+
if (!field.type || typeof field.type !== 'string' || field.type.trim() === '') {
|
|
264
|
+
const message = `ManualConnector: entity '${entityName}' field '${field.name}' missing required property 'type'`
|
|
265
|
+
if (this.strict) {
|
|
266
|
+
throw new Error(message)
|
|
267
|
+
}
|
|
268
|
+
return false
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Validate field.type is valid UnifiedFieldType
|
|
272
|
+
if (!isValidFieldType(field.type)) {
|
|
273
|
+
const validTypes = UNIFIED_FIELD_TYPES.join(', ')
|
|
274
|
+
const message = `ManualConnector: entity '${entityName}' field '${field.name}' has invalid type '${field.type}'. Valid types: ${validTypes}`
|
|
275
|
+
if (this.strict) {
|
|
276
|
+
throw new Error(message)
|
|
277
|
+
}
|
|
278
|
+
return false
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return true
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Collect warnings for an entity without throwing
|
|
286
|
+
*
|
|
287
|
+
* @private
|
|
288
|
+
* @param entity - Entity to check
|
|
289
|
+
* @returns Collected warnings
|
|
290
|
+
*/
|
|
291
|
+
private _collectWarnings(entity: ManualEntityInput): ParseWarning[] {
|
|
292
|
+
const warnings: ParseWarning[] = []
|
|
293
|
+
const entityName = entity.name || '(unnamed)'
|
|
294
|
+
|
|
295
|
+
if (!entity.name || typeof entity.name !== 'string' || entity.name.trim() === '') {
|
|
296
|
+
warnings.push({
|
|
297
|
+
path: entityName,
|
|
298
|
+
message: "Entity missing required field 'name'",
|
|
299
|
+
code: 'MISSING_ENTITY_NAME',
|
|
300
|
+
})
|
|
301
|
+
return warnings // Can't validate further without name
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!entity.endpoint || typeof entity.endpoint !== 'string' || entity.endpoint.trim() === '') {
|
|
305
|
+
warnings.push({
|
|
306
|
+
path: entity.name,
|
|
307
|
+
message: "Entity missing required field 'endpoint'",
|
|
308
|
+
code: 'MISSING_ENTITY_ENDPOINT',
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (entity.fields) {
|
|
313
|
+
for (const [fieldKey, field] of Object.entries(entity.fields)) {
|
|
314
|
+
if (!field.name || typeof field.name !== 'string' || field.name.trim() === '') {
|
|
315
|
+
warnings.push({
|
|
316
|
+
path: `${entity.name}.fields.${fieldKey}`,
|
|
317
|
+
message: "Field missing required property 'name'",
|
|
318
|
+
code: 'MISSING_FIELD_NAME',
|
|
319
|
+
})
|
|
320
|
+
continue
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!field.type || typeof field.type !== 'string' || field.type.trim() === '') {
|
|
324
|
+
warnings.push({
|
|
325
|
+
path: `${entity.name}.fields.${field.name}`,
|
|
326
|
+
message: "Field missing required property 'type'",
|
|
327
|
+
code: 'MISSING_FIELD_TYPE',
|
|
328
|
+
})
|
|
329
|
+
} else if (!isValidFieldType(field.type)) {
|
|
330
|
+
warnings.push({
|
|
331
|
+
path: `${entity.name}.fields.${field.name}`,
|
|
332
|
+
message: `Invalid field type '${field.type}'`,
|
|
333
|
+
code: 'INVALID_FIELD_TYPE',
|
|
334
|
+
})
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return warnings
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Transform validated entity input into UnifiedEntitySchema
|
|
344
|
+
*
|
|
345
|
+
* @private
|
|
346
|
+
* @param entity - Validated entity input
|
|
347
|
+
* @returns Transformed entity schema
|
|
348
|
+
*/
|
|
349
|
+
private _transformEntity(entity: ManualEntityInput): UnifiedEntitySchema {
|
|
350
|
+
const transformedFields: Record<string, UnifiedFieldSchema> = {}
|
|
351
|
+
|
|
352
|
+
if (entity.fields) {
|
|
353
|
+
for (const [fieldKey, field] of Object.entries(entity.fields)) {
|
|
354
|
+
// Skip invalid fields in non-strict mode
|
|
355
|
+
if (!this._validateField(entity.name, fieldKey, field)) {
|
|
356
|
+
continue
|
|
357
|
+
}
|
|
358
|
+
transformedFields[fieldKey] = this._transformField(field)
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const schema: UnifiedEntitySchema = {
|
|
363
|
+
name: entity.name,
|
|
364
|
+
endpoint: entity.endpoint,
|
|
365
|
+
fields: transformedFields,
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Add optional properties if provided
|
|
369
|
+
if (entity.label !== undefined) schema.label = entity.label
|
|
370
|
+
if (entity.labelPlural !== undefined) schema.labelPlural = entity.labelPlural
|
|
371
|
+
if (entity.labelField !== undefined) schema.labelField = entity.labelField
|
|
372
|
+
if (entity.routePrefix !== undefined) schema.routePrefix = entity.routePrefix
|
|
373
|
+
if (entity.idField !== undefined) schema.idField = entity.idField
|
|
374
|
+
if (entity.readOnly !== undefined) schema.readOnly = entity.readOnly
|
|
375
|
+
|
|
376
|
+
// Merge extensions from connector options and entity
|
|
377
|
+
if (this.extensions && Object.keys(this.extensions).length > 0) {
|
|
378
|
+
schema.extensions = { ...this.extensions, ...entity.extensions }
|
|
379
|
+
} else if (entity.extensions) {
|
|
380
|
+
schema.extensions = entity.extensions
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return schema
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Transform field input into UnifiedFieldSchema
|
|
388
|
+
*
|
|
389
|
+
* @private
|
|
390
|
+
* @param field - Field input
|
|
391
|
+
* @returns Transformed field schema
|
|
392
|
+
*/
|
|
393
|
+
private _transformField(field: ManualFieldInput): UnifiedFieldSchema {
|
|
394
|
+
const schema: UnifiedFieldSchema = {
|
|
395
|
+
name: field.name,
|
|
396
|
+
type: field.type as UnifiedFieldType,
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Add optional properties if provided
|
|
400
|
+
if (field.label !== undefined) schema.label = field.label
|
|
401
|
+
if (field.required !== undefined) schema.required = field.required
|
|
402
|
+
if (field.readOnly !== undefined) schema.readOnly = field.readOnly
|
|
403
|
+
if (field.hidden !== undefined) schema.hidden = field.hidden
|
|
404
|
+
if (field.format !== undefined) schema.format = field.format
|
|
405
|
+
if (field.enum !== undefined) schema.enum = field.enum
|
|
406
|
+
if (field.default !== undefined) schema.default = field.default
|
|
407
|
+
if (field.reference !== undefined) schema.reference = field.reference
|
|
408
|
+
if (field.extensions !== undefined) schema.extensions = field.extensions
|
|
409
|
+
|
|
410
|
+
return schema
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export default ManualConnector
|