@xrmforge/typegen 0.1.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/index.d.ts +1295 -0
- package/dist/index.js +2281 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1295 @@
|
|
|
1
|
+
import { TokenCredential } from '@azure/identity';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @xrmforge/typegen - Error Types
|
|
5
|
+
*
|
|
6
|
+
* Centralized error hierarchy for consistent error handling across the framework.
|
|
7
|
+
* Every error carries a machine-readable code, a human-readable message,
|
|
8
|
+
* and optional context for debugging.
|
|
9
|
+
*/
|
|
10
|
+
declare enum ErrorCode {
|
|
11
|
+
AUTH_MISSING_CONFIG = "AUTH_1001",
|
|
12
|
+
AUTH_INVALID_CREDENTIALS = "AUTH_1002",
|
|
13
|
+
AUTH_TOKEN_FAILED = "AUTH_1003",
|
|
14
|
+
AUTH_TOKEN_EXPIRED = "AUTH_1004",
|
|
15
|
+
API_REQUEST_FAILED = "API_2001",
|
|
16
|
+
API_RATE_LIMITED = "API_2002",
|
|
17
|
+
API_NOT_FOUND = "API_2003",
|
|
18
|
+
API_UNAUTHORIZED = "API_2004",
|
|
19
|
+
API_TIMEOUT = "API_2005",
|
|
20
|
+
META_ENTITY_NOT_FOUND = "META_3001",
|
|
21
|
+
META_SOLUTION_NOT_FOUND = "META_3002",
|
|
22
|
+
META_FORM_PARSE_FAILED = "META_3003",
|
|
23
|
+
META_ATTRIBUTE_UNKNOWN_TYPE = "META_3004",
|
|
24
|
+
GEN_OUTPUT_WRITE_FAILED = "GEN_4001",
|
|
25
|
+
GEN_TEMPLATE_FAILED = "GEN_4002",
|
|
26
|
+
GEN_INVALID_IDENTIFIER = "GEN_4003",
|
|
27
|
+
CONFIG_INVALID = "CONFIG_5001",
|
|
28
|
+
CONFIG_FILE_NOT_FOUND = "CONFIG_5002",
|
|
29
|
+
CONFIG_ENV_VAR_MISSING = "CONFIG_5003"
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Base error class for all XrmForge errors.
|
|
33
|
+
* Carries a structured error code and optional context object.
|
|
34
|
+
*/
|
|
35
|
+
declare class XrmForgeError extends Error {
|
|
36
|
+
readonly code: ErrorCode;
|
|
37
|
+
readonly context: Record<string, unknown>;
|
|
38
|
+
constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Authentication-specific error.
|
|
42
|
+
*/
|
|
43
|
+
declare class AuthenticationError extends XrmForgeError {
|
|
44
|
+
constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Dataverse API request error.
|
|
48
|
+
*/
|
|
49
|
+
declare class ApiRequestError extends XrmForgeError {
|
|
50
|
+
readonly statusCode: number | undefined;
|
|
51
|
+
readonly responseBody: string | undefined;
|
|
52
|
+
constructor(code: ErrorCode, message: string, context?: Record<string, unknown> & {
|
|
53
|
+
statusCode?: number;
|
|
54
|
+
responseBody?: string;
|
|
55
|
+
url?: string;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Metadata retrieval or parsing error.
|
|
60
|
+
*/
|
|
61
|
+
declare class MetadataError extends XrmForgeError {
|
|
62
|
+
constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Type generation or file output error.
|
|
66
|
+
*/
|
|
67
|
+
declare class GenerationError extends XrmForgeError {
|
|
68
|
+
constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Configuration validation error.
|
|
72
|
+
*/
|
|
73
|
+
declare class ConfigError extends XrmForgeError {
|
|
74
|
+
constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Type guard to check if an unknown error is an XrmForgeError.
|
|
78
|
+
*/
|
|
79
|
+
declare function isXrmForgeError(error: unknown): error is XrmForgeError;
|
|
80
|
+
/**
|
|
81
|
+
* Type guard for API rate limit errors (HTTP 429).
|
|
82
|
+
*/
|
|
83
|
+
declare function isRateLimitError(error: unknown): error is ApiRequestError;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @xrmforge/typegen - Logger
|
|
87
|
+
*
|
|
88
|
+
* Abstracted logging interface that decouples log output from the modules.
|
|
89
|
+
* Supports: CLI (human-readable), CI/CD (structured JSON), silent (library use).
|
|
90
|
+
*
|
|
91
|
+
* Every logger instance carries a `scope` (e.g. "auth", "metadata", "http")
|
|
92
|
+
* so log consumers can filter by origin module.
|
|
93
|
+
*
|
|
94
|
+
* Consumers can provide their own LogSink to integrate with any logging framework.
|
|
95
|
+
*/
|
|
96
|
+
declare enum LogLevel {
|
|
97
|
+
DEBUG = 0,
|
|
98
|
+
INFO = 1,
|
|
99
|
+
WARN = 2,
|
|
100
|
+
ERROR = 3,
|
|
101
|
+
SILENT = 4
|
|
102
|
+
}
|
|
103
|
+
interface LogEntry {
|
|
104
|
+
level: LogLevel;
|
|
105
|
+
scope: string;
|
|
106
|
+
message: string;
|
|
107
|
+
context?: Record<string, unknown>;
|
|
108
|
+
timestamp: Date;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Interface for log output destinations.
|
|
112
|
+
* Implement this to route XrmForge logs into your own logging system.
|
|
113
|
+
*/
|
|
114
|
+
interface LogSink {
|
|
115
|
+
write(entry: LogEntry): void;
|
|
116
|
+
/**
|
|
117
|
+
* Write an inline progress update (no trailing newline).
|
|
118
|
+
* Used for long-running operations where each entity gets a status indicator.
|
|
119
|
+
*
|
|
120
|
+
* Sinks that don't support inline progress (e.g. JSON) should fall back
|
|
121
|
+
* to writing a regular INFO entry.
|
|
122
|
+
*/
|
|
123
|
+
writeProgress(message: string): void;
|
|
124
|
+
/**
|
|
125
|
+
* Complete an inline progress line with a trailing message and newline.
|
|
126
|
+
*/
|
|
127
|
+
writeProgressEnd(message: string): void;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Default CLI log sink with human-readable output and ANSI color indicators.
|
|
131
|
+
*/
|
|
132
|
+
declare class ConsoleLogSink implements LogSink {
|
|
133
|
+
private static readonly LEVEL_PREFIX;
|
|
134
|
+
write(entry: LogEntry): void;
|
|
135
|
+
writeProgress(message: string): void;
|
|
136
|
+
writeProgressEnd(message: string): void;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Structured JSON log sink for CI/CD pipelines and machine-readable output.
|
|
140
|
+
*/
|
|
141
|
+
declare class JsonLogSink implements LogSink {
|
|
142
|
+
write(entry: LogEntry): void;
|
|
143
|
+
writeProgress(message: string): void;
|
|
144
|
+
writeProgressEnd(message: string): void;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Silent log sink that discards all output. Used when running as a library.
|
|
148
|
+
*/
|
|
149
|
+
declare class SilentLogSink implements LogSink {
|
|
150
|
+
write(_entry: LogEntry): void;
|
|
151
|
+
writeProgress(_message: string): void;
|
|
152
|
+
writeProgressEnd(_message: string): void;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Logger with scope prefix and configurable sink/level.
|
|
156
|
+
*
|
|
157
|
+
* Usage:
|
|
158
|
+
* ```ts
|
|
159
|
+
* const log = createLogger('auth');
|
|
160
|
+
* log.info('Token acquired', { expiresIn: '3600s' });
|
|
161
|
+
* // Output: [INF] [auth] Token acquired
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare class Logger {
|
|
165
|
+
private readonly scope;
|
|
166
|
+
private readonly getSink;
|
|
167
|
+
private readonly getMinLevel;
|
|
168
|
+
constructor(scope: string, getSink: () => LogSink, getMinLevel: () => LogLevel);
|
|
169
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
170
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
171
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
172
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
173
|
+
/**
|
|
174
|
+
* Write an inline progress update (no newline).
|
|
175
|
+
*/
|
|
176
|
+
progress(message: string): void;
|
|
177
|
+
/**
|
|
178
|
+
* Complete an inline progress line.
|
|
179
|
+
*/
|
|
180
|
+
progressEnd(message: string): void;
|
|
181
|
+
private log;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Configure logging globally for all @xrmforge modules.
|
|
185
|
+
* Can be called at any time; existing loggers will pick up the new configuration
|
|
186
|
+
* automatically because they reference the shared state via closures.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```ts
|
|
190
|
+
* configureLogging({ sink: new JsonLogSink(), minLevel: LogLevel.WARN });
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
declare function configureLogging(options: {
|
|
194
|
+
sink?: LogSink;
|
|
195
|
+
minLevel?: LogLevel;
|
|
196
|
+
}): void;
|
|
197
|
+
/**
|
|
198
|
+
* Create a scoped logger instance. All modules should use this instead of console.log.
|
|
199
|
+
*
|
|
200
|
+
* The logger reads the global sink and minLevel at each log call (not at creation time),
|
|
201
|
+
* so `configureLogging()` takes effect even on previously created loggers.
|
|
202
|
+
*
|
|
203
|
+
* @param scope - Module identifier shown in log output, e.g. "auth", "metadata", "http"
|
|
204
|
+
*/
|
|
205
|
+
declare function createLogger(scope: string): Logger;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @xrmforge/typegen - Authentication Module
|
|
209
|
+
*
|
|
210
|
+
* Handles authentication to Dataverse Web API using MSAL (@azure/identity).
|
|
211
|
+
* Supports: Client Credentials (Service Principal), Interactive Browser, Device Code.
|
|
212
|
+
*
|
|
213
|
+
* Token acquisition and caching is handled by the DataverseHttpClient.
|
|
214
|
+
* This module is responsible only for creating the correct TokenCredential.
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
type AuthMethod = 'client-credentials' | 'interactive' | 'device-code' | 'token';
|
|
218
|
+
interface ClientCredentialsAuth {
|
|
219
|
+
method: 'client-credentials';
|
|
220
|
+
tenantId: string;
|
|
221
|
+
clientId: string;
|
|
222
|
+
clientSecret: string;
|
|
223
|
+
}
|
|
224
|
+
interface InteractiveAuth {
|
|
225
|
+
method: 'interactive';
|
|
226
|
+
tenantId?: string;
|
|
227
|
+
clientId?: string;
|
|
228
|
+
}
|
|
229
|
+
interface DeviceCodeAuth {
|
|
230
|
+
method: 'device-code';
|
|
231
|
+
tenantId?: string;
|
|
232
|
+
clientId?: string;
|
|
233
|
+
}
|
|
234
|
+
interface TokenAuth {
|
|
235
|
+
method: 'token';
|
|
236
|
+
/** Pre-acquired Bearer token (e.g. from TokenVault, Key Vault, CI/CD secret) */
|
|
237
|
+
token: string;
|
|
238
|
+
}
|
|
239
|
+
type AuthConfig = ClientCredentialsAuth | InteractiveAuth | DeviceCodeAuth | TokenAuth;
|
|
240
|
+
/**
|
|
241
|
+
* Creates an Azure Identity TokenCredential from the provided auth configuration.
|
|
242
|
+
* Validates required fields before attempting credential creation.
|
|
243
|
+
*
|
|
244
|
+
* @throws {AuthenticationError} if required configuration values are missing
|
|
245
|
+
*/
|
|
246
|
+
declare function createCredential(config: AuthConfig): TokenCredential;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @xrmforge/typegen - Dataverse HTTP Client
|
|
250
|
+
*
|
|
251
|
+
* Resilient HTTP client for the Dataverse Web API.
|
|
252
|
+
*
|
|
253
|
+
* Features:
|
|
254
|
+
* - Token caching with 5-minute buffer before expiry
|
|
255
|
+
* - Automatic retry with exponential backoff and jitter
|
|
256
|
+
* - Rate limit awareness (HTTP 429 with Retry-After)
|
|
257
|
+
* - Request timeout via AbortController
|
|
258
|
+
* - Concurrency control (semaphore pattern, NOT recursive)
|
|
259
|
+
* - Automatic OData paging via @odata.nextLink with safety limit
|
|
260
|
+
* - Input sanitization helpers against OData injection
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
interface HttpClientOptions {
|
|
264
|
+
/** Dataverse environment URL, e.g. "https://myorg.crm4.dynamics.com" */
|
|
265
|
+
environmentUrl: string;
|
|
266
|
+
/** Azure Identity credential */
|
|
267
|
+
credential: TokenCredential;
|
|
268
|
+
/** API version (default: "v9.2") */
|
|
269
|
+
apiVersion?: string;
|
|
270
|
+
/** Maximum retry attempts for transient errors (default: 3) */
|
|
271
|
+
maxRetries?: number;
|
|
272
|
+
/** Base delay in ms for exponential backoff (default: 1000) */
|
|
273
|
+
retryBaseDelayMs?: number;
|
|
274
|
+
/** Request timeout in ms (default: 30000) */
|
|
275
|
+
timeoutMs?: number;
|
|
276
|
+
/** Maximum concurrent requests to Dataverse (default: 5) */
|
|
277
|
+
maxConcurrency?: number;
|
|
278
|
+
/** Maximum pages to follow via @odata.nextLink (default: 100, safety limit) */
|
|
279
|
+
maxPages?: number;
|
|
280
|
+
/** Maximum consecutive HTTP 429 retries before giving up (default: 10) */
|
|
281
|
+
maxRateLimitRetries?: number;
|
|
282
|
+
/**
|
|
283
|
+
* Read-only mode (default: true).
|
|
284
|
+
* When true, the client will ONLY allow GET requests and throw an error
|
|
285
|
+
* for any POST, PATCH, PUT, or DELETE attempt.
|
|
286
|
+
*
|
|
287
|
+
* SAFETY: XrmForge typegen is a read-only tool. It must NEVER modify
|
|
288
|
+
* data in Dataverse environments. This flag defaults to true and should
|
|
289
|
+
* only be set to false for the @xrmforge/webapi package (future).
|
|
290
|
+
*/
|
|
291
|
+
readOnly?: boolean;
|
|
292
|
+
}
|
|
293
|
+
declare class DataverseHttpClient {
|
|
294
|
+
private readonly baseUrl;
|
|
295
|
+
private readonly apiVersion;
|
|
296
|
+
private readonly credential;
|
|
297
|
+
private readonly maxRetries;
|
|
298
|
+
private readonly retryBaseDelayMs;
|
|
299
|
+
private readonly timeoutMs;
|
|
300
|
+
private readonly maxConcurrency;
|
|
301
|
+
private readonly maxPages;
|
|
302
|
+
private readonly maxRateLimitRetries;
|
|
303
|
+
private readonly readOnly;
|
|
304
|
+
private cachedToken;
|
|
305
|
+
private activeConcurrentRequests;
|
|
306
|
+
private readonly waitQueue;
|
|
307
|
+
constructor(options: HttpClientOptions);
|
|
308
|
+
/**
|
|
309
|
+
* Full API base URL, e.g. "https://myorg.crm4.dynamics.com/api/data/v9.2"
|
|
310
|
+
*/
|
|
311
|
+
get apiUrl(): string;
|
|
312
|
+
/**
|
|
313
|
+
* Execute a GET request against the Dataverse Web API.
|
|
314
|
+
* Handles token caching, retries, rate limits, and timeout.
|
|
315
|
+
*
|
|
316
|
+
* @param path - API path (relative or absolute URL)
|
|
317
|
+
* @param signal - Optional AbortSignal to cancel the request
|
|
318
|
+
*/
|
|
319
|
+
get<T>(path: string, signal?: AbortSignal): Promise<T>;
|
|
320
|
+
/**
|
|
321
|
+
* Execute a GET request and automatically follow @odata.nextLink for paging.
|
|
322
|
+
* Returns all pages combined into a single array.
|
|
323
|
+
*
|
|
324
|
+
* Safety: Stops after `maxPages` iterations to prevent infinite loops.
|
|
325
|
+
*
|
|
326
|
+
* @param path - API path (relative or absolute URL)
|
|
327
|
+
* @param signal - Optional AbortSignal to cancel the request
|
|
328
|
+
*/
|
|
329
|
+
getAll<T>(path: string, signal?: AbortSignal): Promise<T[]>;
|
|
330
|
+
/**
|
|
331
|
+
* Returns true if this client is in read-only mode (the safe default).
|
|
332
|
+
*/
|
|
333
|
+
get isReadOnly(): boolean;
|
|
334
|
+
/**
|
|
335
|
+
* Assert that a non-GET operation is allowed.
|
|
336
|
+
* Throws immediately if the client is in read-only mode.
|
|
337
|
+
*
|
|
338
|
+
* @throws {ApiRequestError} always in read-only mode
|
|
339
|
+
* @internal This method exists so that future packages (e.g. @xrmforge/webapi)
|
|
340
|
+
* can reuse the HTTP client for write operations when readOnly is explicitly false.
|
|
341
|
+
*/
|
|
342
|
+
assertWriteAllowed(operation: string): void;
|
|
343
|
+
/**
|
|
344
|
+
* Validate that a value is a safe OData identifier (entity name, attribute name).
|
|
345
|
+
* Prevents OData injection by allowing only: starts with letter/underscore,
|
|
346
|
+
* followed by alphanumeric/underscore.
|
|
347
|
+
*
|
|
348
|
+
* @throws {ApiRequestError} if the value contains invalid characters
|
|
349
|
+
*/
|
|
350
|
+
static sanitizeIdentifier(value: string): string;
|
|
351
|
+
/**
|
|
352
|
+
* Validate that a value is a properly formatted GUID.
|
|
353
|
+
*
|
|
354
|
+
* @throws {ApiRequestError} if the format is invalid
|
|
355
|
+
*/
|
|
356
|
+
static sanitizeGuid(value: string): string;
|
|
357
|
+
/**
|
|
358
|
+
* Escape a string for use inside OData single-quoted string literals.
|
|
359
|
+
* Doubles single quotes to prevent injection.
|
|
360
|
+
*/
|
|
361
|
+
static escapeODataString(value: string): string;
|
|
362
|
+
private getToken;
|
|
363
|
+
/**
|
|
364
|
+
* Execute a request within the concurrency semaphore.
|
|
365
|
+
* The semaphore is acquired ONCE per logical request. Retries happen
|
|
366
|
+
* INSIDE the semaphore to avoid the recursive slot exhaustion bug.
|
|
367
|
+
*/
|
|
368
|
+
private executeWithConcurrency;
|
|
369
|
+
private acquireSlot;
|
|
370
|
+
private releaseSlot;
|
|
371
|
+
private executeWithRetry;
|
|
372
|
+
private handleHttpError;
|
|
373
|
+
private resolveUrl;
|
|
374
|
+
private calculateBackoff;
|
|
375
|
+
private sleep;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* @xrmforge/typegen - Metadata Types
|
|
380
|
+
*
|
|
381
|
+
* TypeScript interfaces for Dataverse Metadata API responses.
|
|
382
|
+
* These types model the JSON structures returned by the EntityDefinitions,
|
|
383
|
+
* Attributes, SystemForms, and GlobalOptionSetDefinitions endpoints.
|
|
384
|
+
*/
|
|
385
|
+
interface LocalizedLabel {
|
|
386
|
+
Label: string;
|
|
387
|
+
LanguageCode: number;
|
|
388
|
+
}
|
|
389
|
+
interface Label {
|
|
390
|
+
LocalizedLabels: LocalizedLabel[];
|
|
391
|
+
UserLocalizedLabel: LocalizedLabel | null;
|
|
392
|
+
}
|
|
393
|
+
interface EntityMetadata {
|
|
394
|
+
LogicalName: string;
|
|
395
|
+
SchemaName: string;
|
|
396
|
+
EntitySetName: string;
|
|
397
|
+
DisplayName: Label;
|
|
398
|
+
PrimaryIdAttribute: string;
|
|
399
|
+
PrimaryNameAttribute: string;
|
|
400
|
+
OwnershipType: string;
|
|
401
|
+
IsCustomEntity: boolean;
|
|
402
|
+
LogicalCollectionName: string;
|
|
403
|
+
MetadataId: string;
|
|
404
|
+
Attributes?: AttributeMetadata[];
|
|
405
|
+
}
|
|
406
|
+
interface AttributeMetadata {
|
|
407
|
+
'@odata.type'?: string;
|
|
408
|
+
LogicalName: string;
|
|
409
|
+
SchemaName: string;
|
|
410
|
+
AttributeType: string;
|
|
411
|
+
AttributeTypeName?: {
|
|
412
|
+
Value: string;
|
|
413
|
+
};
|
|
414
|
+
DisplayName: Label;
|
|
415
|
+
IsPrimaryId: boolean;
|
|
416
|
+
IsPrimaryName: boolean;
|
|
417
|
+
RequiredLevel: {
|
|
418
|
+
Value: string;
|
|
419
|
+
};
|
|
420
|
+
IsValidForRead: boolean;
|
|
421
|
+
IsValidForCreate: boolean;
|
|
422
|
+
IsValidForUpdate: boolean;
|
|
423
|
+
MetadataId: string;
|
|
424
|
+
}
|
|
425
|
+
interface StringAttributeMetadata extends AttributeMetadata {
|
|
426
|
+
MaxLength: number;
|
|
427
|
+
FormatName: {
|
|
428
|
+
Value: string;
|
|
429
|
+
} | null;
|
|
430
|
+
}
|
|
431
|
+
interface IntegerAttributeMetadata extends AttributeMetadata {
|
|
432
|
+
MaxValue: number;
|
|
433
|
+
MinValue: number;
|
|
434
|
+
}
|
|
435
|
+
interface DecimalAttributeMetadata extends AttributeMetadata {
|
|
436
|
+
MaxValue: number;
|
|
437
|
+
MinValue: number;
|
|
438
|
+
Precision: number;
|
|
439
|
+
}
|
|
440
|
+
interface MoneyAttributeMetadata extends AttributeMetadata {
|
|
441
|
+
MaxValue: number;
|
|
442
|
+
MinValue: number;
|
|
443
|
+
Precision: number;
|
|
444
|
+
PrecisionSource: number;
|
|
445
|
+
}
|
|
446
|
+
interface DateTimeAttributeMetadata extends AttributeMetadata {
|
|
447
|
+
DateTimeBehavior: {
|
|
448
|
+
Value: string;
|
|
449
|
+
};
|
|
450
|
+
Format: string;
|
|
451
|
+
}
|
|
452
|
+
interface LookupAttributeMetadata extends AttributeMetadata {
|
|
453
|
+
Targets: string[];
|
|
454
|
+
}
|
|
455
|
+
interface PicklistAttributeMetadata extends AttributeMetadata {
|
|
456
|
+
OptionSet: OptionSetMetadata | null;
|
|
457
|
+
GlobalOptionSet: OptionSetMetadata | null;
|
|
458
|
+
}
|
|
459
|
+
interface StatusAttributeMetadata extends AttributeMetadata {
|
|
460
|
+
OptionSet: OptionSetMetadata | null;
|
|
461
|
+
}
|
|
462
|
+
interface StateAttributeMetadata extends AttributeMetadata {
|
|
463
|
+
OptionSet: OptionSetMetadata | null;
|
|
464
|
+
}
|
|
465
|
+
interface OptionMetadata {
|
|
466
|
+
Value: number;
|
|
467
|
+
Label: Label;
|
|
468
|
+
Description: Label;
|
|
469
|
+
Color: string | null;
|
|
470
|
+
}
|
|
471
|
+
interface OptionSetMetadata {
|
|
472
|
+
'@odata.type'?: string;
|
|
473
|
+
Name: string;
|
|
474
|
+
DisplayName: Label;
|
|
475
|
+
IsCustomOptionSet: boolean;
|
|
476
|
+
IsGlobal: boolean;
|
|
477
|
+
OptionSetType: string;
|
|
478
|
+
Options: OptionMetadata[];
|
|
479
|
+
MetadataId: string;
|
|
480
|
+
}
|
|
481
|
+
interface SystemFormMetadata {
|
|
482
|
+
name: string;
|
|
483
|
+
formid: string;
|
|
484
|
+
formxml: string;
|
|
485
|
+
description: string | null;
|
|
486
|
+
isdefault: boolean;
|
|
487
|
+
}
|
|
488
|
+
/** Parsed data-bound control from FormXml (bound to an attribute) */
|
|
489
|
+
interface FormControl {
|
|
490
|
+
/** Control ID (often same as datafieldname) */
|
|
491
|
+
id: string;
|
|
492
|
+
/** Attribute logical name this control is bound to */
|
|
493
|
+
datafieldname: string;
|
|
494
|
+
/** Control class ID (GUID identifying the control type) */
|
|
495
|
+
classid: string;
|
|
496
|
+
}
|
|
497
|
+
/** Type of special (non-data-bound) control on a form */
|
|
498
|
+
type SpecialControlType = 'subgrid' | 'editablegrid' | 'quickview' | 'webresource' | 'iframe' | 'notes' | 'map' | 'timer' | 'unknown';
|
|
499
|
+
/** Parsed special control from FormXml (subgrid, quick view, web resource, etc.) */
|
|
500
|
+
interface FormSpecialControl {
|
|
501
|
+
/** Control ID (used for getControl) */
|
|
502
|
+
id: string;
|
|
503
|
+
/** Control class ID (GUID) */
|
|
504
|
+
classid: string;
|
|
505
|
+
/** Resolved control type */
|
|
506
|
+
controlType: SpecialControlType;
|
|
507
|
+
/** Target entity for subgrids (from parameters) */
|
|
508
|
+
targetEntityType?: string;
|
|
509
|
+
/** Relationship name for subgrids (from parameters) */
|
|
510
|
+
relationshipName?: string;
|
|
511
|
+
/** Web resource name (for web resource controls) */
|
|
512
|
+
webResourceName?: string;
|
|
513
|
+
}
|
|
514
|
+
/** Parsed tab from FormXml */
|
|
515
|
+
interface FormTab {
|
|
516
|
+
name: string;
|
|
517
|
+
/** Tab label (for display, may be localized) */
|
|
518
|
+
label?: string;
|
|
519
|
+
/** Whether the tab is visible by default */
|
|
520
|
+
visible?: boolean;
|
|
521
|
+
sections: FormSection[];
|
|
522
|
+
}
|
|
523
|
+
/** Parsed section from FormXml */
|
|
524
|
+
interface FormSection {
|
|
525
|
+
name: string;
|
|
526
|
+
/** Section label */
|
|
527
|
+
label?: string;
|
|
528
|
+
/** Whether the section is visible by default */
|
|
529
|
+
visible?: boolean;
|
|
530
|
+
controls: FormControl[];
|
|
531
|
+
/** Special controls in this section (subgrids, quick views, etc.) */
|
|
532
|
+
specialControls: FormSpecialControl[];
|
|
533
|
+
}
|
|
534
|
+
/** Parsed form structure */
|
|
535
|
+
interface ParsedForm {
|
|
536
|
+
name: string;
|
|
537
|
+
formId: string;
|
|
538
|
+
isDefault: boolean;
|
|
539
|
+
tabs: FormTab[];
|
|
540
|
+
/** All data-bound controls across all tabs/sections (flattened) */
|
|
541
|
+
allControls: FormControl[];
|
|
542
|
+
/** All special controls across all tabs/sections (flattened) */
|
|
543
|
+
allSpecialControls: FormSpecialControl[];
|
|
544
|
+
}
|
|
545
|
+
interface OneToManyRelationshipMetadata {
|
|
546
|
+
SchemaName: string;
|
|
547
|
+
ReferencingEntity: string;
|
|
548
|
+
ReferencingAttribute: string;
|
|
549
|
+
ReferencedEntity: string;
|
|
550
|
+
ReferencedAttribute: string;
|
|
551
|
+
MetadataId: string;
|
|
552
|
+
}
|
|
553
|
+
interface ManyToManyRelationshipMetadata {
|
|
554
|
+
SchemaName: string;
|
|
555
|
+
Entity1LogicalName: string;
|
|
556
|
+
Entity2LogicalName: string;
|
|
557
|
+
IntersectEntityName: string;
|
|
558
|
+
MetadataId: string;
|
|
559
|
+
}
|
|
560
|
+
interface SolutionComponent {
|
|
561
|
+
objectid: string;
|
|
562
|
+
componenttype: number;
|
|
563
|
+
}
|
|
564
|
+
/** Complete metadata for a single entity, ready for type generation */
|
|
565
|
+
interface EntityTypeInfo {
|
|
566
|
+
entity: EntityMetadata;
|
|
567
|
+
attributes: AttributeMetadata[];
|
|
568
|
+
picklistAttributes: PicklistAttributeMetadata[];
|
|
569
|
+
lookupAttributes: LookupAttributeMetadata[];
|
|
570
|
+
statusAttributes: StatusAttributeMetadata[];
|
|
571
|
+
stateAttributes: StateAttributeMetadata[];
|
|
572
|
+
forms: ParsedForm[];
|
|
573
|
+
oneToManyRelationships: OneToManyRelationshipMetadata[];
|
|
574
|
+
manyToManyRelationships: ManyToManyRelationshipMetadata[];
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* @xrmforge/typegen - Metadata Client
|
|
579
|
+
*
|
|
580
|
+
* High-level client for querying Dataverse Metadata API endpoints.
|
|
581
|
+
* Built on top of DataverseHttpClient for resilient HTTP communication.
|
|
582
|
+
*
|
|
583
|
+
* Provides methods for:
|
|
584
|
+
* - Entity metadata with attributes
|
|
585
|
+
* - Typed attribute queries (Picklist, Lookup, Status/State)
|
|
586
|
+
* - Form metadata (SystemForms + FormXml parsing)
|
|
587
|
+
* - Global OptionSet definitions
|
|
588
|
+
* - Solution-based entity filtering
|
|
589
|
+
* - Relationship metadata (1:N, N:N)
|
|
590
|
+
*/
|
|
591
|
+
|
|
592
|
+
declare class MetadataClient {
|
|
593
|
+
private readonly http;
|
|
594
|
+
constructor(httpClient: DataverseHttpClient);
|
|
595
|
+
/**
|
|
596
|
+
* Get metadata for a single entity by LogicalName, including all attributes.
|
|
597
|
+
*
|
|
598
|
+
* @throws {MetadataError} if the entity is not found
|
|
599
|
+
*/
|
|
600
|
+
getEntityWithAttributes(logicalName: string): Promise<EntityMetadata>;
|
|
601
|
+
/**
|
|
602
|
+
* List all entities (without attributes) for discovery.
|
|
603
|
+
* Use `$filter` parameter to narrow results.
|
|
604
|
+
*/
|
|
605
|
+
listEntities(filter?: string): Promise<EntityMetadata[]>;
|
|
606
|
+
/**
|
|
607
|
+
* Get all Picklist attributes with their OptionSets for an entity.
|
|
608
|
+
* Includes both local and global OptionSets.
|
|
609
|
+
*/
|
|
610
|
+
getPicklistAttributes(logicalName: string): Promise<PicklistAttributeMetadata[]>;
|
|
611
|
+
/**
|
|
612
|
+
* Get all Lookup attributes with their target entity names.
|
|
613
|
+
*/
|
|
614
|
+
getLookupAttributes(logicalName: string): Promise<LookupAttributeMetadata[]>;
|
|
615
|
+
/**
|
|
616
|
+
* Get Status attributes (statuscode) with their OptionSets.
|
|
617
|
+
*/
|
|
618
|
+
getStatusAttributes(logicalName: string): Promise<StatusAttributeMetadata[]>;
|
|
619
|
+
/**
|
|
620
|
+
* Get State attributes (statecode) with their OptionSets.
|
|
621
|
+
*/
|
|
622
|
+
getStateAttributes(logicalName: string): Promise<StateAttributeMetadata[]>;
|
|
623
|
+
/**
|
|
624
|
+
* Get and parse Main forms (type=2) for an entity.
|
|
625
|
+
* Returns parsed form structures with tabs, sections, and controls.
|
|
626
|
+
*/
|
|
627
|
+
getMainForms(logicalName: string): Promise<ParsedForm[]>;
|
|
628
|
+
/**
|
|
629
|
+
* Get a global OptionSet by its exact name.
|
|
630
|
+
*/
|
|
631
|
+
getGlobalOptionSet(name: string): Promise<OptionSetMetadata>;
|
|
632
|
+
/**
|
|
633
|
+
* List all global OptionSets (names and types only).
|
|
634
|
+
*/
|
|
635
|
+
listGlobalOptionSets(): Promise<OptionSetMetadata[]>;
|
|
636
|
+
/**
|
|
637
|
+
* Get all 1:N relationships where this entity is the referenced (parent) entity.
|
|
638
|
+
*/
|
|
639
|
+
getOneToManyRelationships(logicalName: string): Promise<OneToManyRelationshipMetadata[]>;
|
|
640
|
+
/**
|
|
641
|
+
* Get all N:N relationships for an entity.
|
|
642
|
+
*/
|
|
643
|
+
getManyToManyRelationships(logicalName: string): Promise<ManyToManyRelationshipMetadata[]>;
|
|
644
|
+
/**
|
|
645
|
+
* Get all entity LogicalNames that belong to a specific solution.
|
|
646
|
+
* Resolves SolutionComponent MetadataIds to EntityDefinition LogicalNames.
|
|
647
|
+
*
|
|
648
|
+
* @param solutionUniqueName - The unique name of the solution
|
|
649
|
+
* @returns Array of entity LogicalNames (e.g. ["account", "contact"])
|
|
650
|
+
*/
|
|
651
|
+
getEntityNamesForSolution(solutionUniqueName: string): Promise<string[]>;
|
|
652
|
+
/**
|
|
653
|
+
* Get all entity LogicalNames from multiple solutions, merged and deduplicated.
|
|
654
|
+
*
|
|
655
|
+
* @param solutionUniqueNames - Array of solution unique names
|
|
656
|
+
* @returns Deduplicated array of entity LogicalNames
|
|
657
|
+
*/
|
|
658
|
+
getEntityNamesForSolutions(solutionUniqueNames: string[]): Promise<string[]>;
|
|
659
|
+
/**
|
|
660
|
+
* Fetch complete metadata for a single entity: all attributes (typed),
|
|
661
|
+
* forms, and relationships. This is the primary method for type generation.
|
|
662
|
+
*
|
|
663
|
+
* Makes 7 parallel API calls per entity for optimal performance.
|
|
664
|
+
*/
|
|
665
|
+
getEntityTypeInfo(logicalName: string): Promise<EntityTypeInfo>;
|
|
666
|
+
/**
|
|
667
|
+
* Fetch complete metadata for multiple entities in parallel.
|
|
668
|
+
* Respects the HTTP client's concurrency limit automatically.
|
|
669
|
+
*/
|
|
670
|
+
getMultipleEntityTypeInfos(logicalNames: string[]): Promise<EntityTypeInfo[]>;
|
|
671
|
+
private getRelationships;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* @xrmforge/typegen - Metadata Cache
|
|
676
|
+
*
|
|
677
|
+
* File-system based metadata cache using Dataverse's RetrieveMetadataChanges
|
|
678
|
+
* ServerVersionStamp for efficient delta detection.
|
|
679
|
+
*
|
|
680
|
+
* On first run: full metadata retrieval, saved to .xrmforge/cache/metadata.json
|
|
681
|
+
* On subsequent runs: delta query with stored VersionStamp, only changed entities refreshed
|
|
682
|
+
* On expired stamp (90-day window or system maintenance): automatic full reload
|
|
683
|
+
*
|
|
684
|
+
* @see https://learn.microsoft.com/en-us/power-apps/developer/data-platform/cache-schema-data
|
|
685
|
+
*/
|
|
686
|
+
|
|
687
|
+
interface CacheManifest {
|
|
688
|
+
/** XrmForge version that created this cache */
|
|
689
|
+
version: string;
|
|
690
|
+
/** Dataverse environment URL */
|
|
691
|
+
environmentUrl: string;
|
|
692
|
+
/** ServerVersionStamp from last RetrieveMetadataChanges call */
|
|
693
|
+
serverVersionStamp: string | null;
|
|
694
|
+
/** ISO timestamp of last full or delta refresh */
|
|
695
|
+
lastRefreshed: string;
|
|
696
|
+
/** Entity logical names in this cache */
|
|
697
|
+
entities: string[];
|
|
698
|
+
}
|
|
699
|
+
interface CacheData {
|
|
700
|
+
manifest: CacheManifest;
|
|
701
|
+
entityTypeInfos: Record<string, EntityTypeInfo>;
|
|
702
|
+
}
|
|
703
|
+
declare class MetadataCache {
|
|
704
|
+
private readonly cacheDir;
|
|
705
|
+
private readonly cacheFilePath;
|
|
706
|
+
/**
|
|
707
|
+
* @param projectRoot - Root directory of the project (where .xrmforge/ will be created)
|
|
708
|
+
*/
|
|
709
|
+
constructor(projectRoot: string);
|
|
710
|
+
/**
|
|
711
|
+
* Load cached metadata from disk.
|
|
712
|
+
* Returns null if no cache exists, cache is for a different environment,
|
|
713
|
+
* or cache format is incompatible.
|
|
714
|
+
*/
|
|
715
|
+
load(environmentUrl: string): Promise<CacheData | null>;
|
|
716
|
+
/**
|
|
717
|
+
* Save metadata to the file-system cache.
|
|
718
|
+
*/
|
|
719
|
+
save(environmentUrl: string, entityTypeInfos: Record<string, EntityTypeInfo>, serverVersionStamp: string | null): Promise<void>;
|
|
720
|
+
/**
|
|
721
|
+
* Get the stored ServerVersionStamp for delta queries.
|
|
722
|
+
* Returns null if no cache exists.
|
|
723
|
+
*/
|
|
724
|
+
getVersionStamp(environmentUrl: string): Promise<string | null>;
|
|
725
|
+
/**
|
|
726
|
+
* Update specific entities in the cache (delta update).
|
|
727
|
+
* Merges new/changed entities into the existing cache.
|
|
728
|
+
*/
|
|
729
|
+
updateEntities(environmentUrl: string, updatedEntities: Record<string, EntityTypeInfo>, newVersionStamp: string | null): Promise<void>;
|
|
730
|
+
/**
|
|
731
|
+
* Remove specific entities from the cache (for deleted entities).
|
|
732
|
+
*/
|
|
733
|
+
removeEntities(environmentUrl: string, deletedEntityNames: string[], newVersionStamp: string | null): Promise<void>;
|
|
734
|
+
/**
|
|
735
|
+
* Delete the entire cache.
|
|
736
|
+
*/
|
|
737
|
+
clear(): Promise<void>;
|
|
738
|
+
/**
|
|
739
|
+
* Check if a cache file exists.
|
|
740
|
+
*/
|
|
741
|
+
exists(): Promise<boolean>;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* @xrmforge/typegen - Label Utilities
|
|
746
|
+
*
|
|
747
|
+
* Extracts and formats localized labels from Dataverse metadata.
|
|
748
|
+
* Supports dual-language output (Goldene Regel 15):
|
|
749
|
+
* - Primary language for identifiers and first JSDoc line
|
|
750
|
+
* - Secondary language as optional addition in JSDoc
|
|
751
|
+
*
|
|
752
|
+
* Format: "Primary Label | Sekundäres Label"
|
|
753
|
+
* If secondary language is not available: "Primary Label" only.
|
|
754
|
+
*/
|
|
755
|
+
|
|
756
|
+
interface LabelConfig {
|
|
757
|
+
/** Primary language LCID (used for identifiers and first JSDoc line). Default: 1033 (English) */
|
|
758
|
+
primaryLanguage: number;
|
|
759
|
+
/** Optional secondary language LCID (added as comment). Example: 1031 (German) */
|
|
760
|
+
secondaryLanguage?: number;
|
|
761
|
+
}
|
|
762
|
+
/** Default: English only */
|
|
763
|
+
declare const DEFAULT_LABEL_CONFIG: LabelConfig;
|
|
764
|
+
/**
|
|
765
|
+
* Extract a label string for the primary language.
|
|
766
|
+
* Falls back to UserLocalizedLabel if the specific LCID is not found.
|
|
767
|
+
* Returns empty string if no label is available.
|
|
768
|
+
*/
|
|
769
|
+
declare function getPrimaryLabel(label: Label | null | undefined, config: LabelConfig): string;
|
|
770
|
+
/**
|
|
771
|
+
* Extract a dual-language JSDoc string.
|
|
772
|
+
* Returns "Primary | Secondary" if both languages available,
|
|
773
|
+
* or just "Primary" if secondary is missing or not configured.
|
|
774
|
+
*/
|
|
775
|
+
declare function getJSDocLabel(label: Label | null | undefined, config: LabelConfig): string;
|
|
776
|
+
/**
|
|
777
|
+
* Convert a label string to a valid TypeScript identifier (PascalCase).
|
|
778
|
+
* Transliterates German umlauts (ä to ae, ö to oe, ü to ue, ß to ss),
|
|
779
|
+
* then removes remaining invalid characters.
|
|
780
|
+
*
|
|
781
|
+
* @returns A valid TypeScript identifier, or null if the label cannot be converted
|
|
782
|
+
*/
|
|
783
|
+
declare function labelToIdentifier(label: string): string | null;
|
|
784
|
+
/**
|
|
785
|
+
* Generate unique enum member names from OptionSet labels.
|
|
786
|
+
* Handles duplicates by appending _{Value} to colliding names.
|
|
787
|
+
* Falls back to Value_{numericValue} for unconvertible labels.
|
|
788
|
+
*
|
|
789
|
+
* @param options - Array of { Value, Label } from OptionSetMetadata
|
|
790
|
+
* @param config - Label configuration for language selection
|
|
791
|
+
* @returns Array of { name, value, jsDocLabel } for enum generation
|
|
792
|
+
*/
|
|
793
|
+
declare function generateEnumMembers(options: Array<{
|
|
794
|
+
Value: number;
|
|
795
|
+
Label: Label;
|
|
796
|
+
}>, config: LabelConfig): Array<{
|
|
797
|
+
name: string;
|
|
798
|
+
value: number;
|
|
799
|
+
jsDocLabel: string;
|
|
800
|
+
}>;
|
|
801
|
+
/**
|
|
802
|
+
* Build the LabelLanguages query parameter for Dataverse Metadata API.
|
|
803
|
+
* Returns the parameter string to append to metadata queries.
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* getLabelLanguagesParam({ primaryLanguage: 1033, secondaryLanguage: 1031 })
|
|
807
|
+
* // Returns "&LabelLanguages=1033,1031"
|
|
808
|
+
*/
|
|
809
|
+
declare function getLabelLanguagesParam(config: LabelConfig): string;
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* @xrmforge/typegen - XML Parser Abstraction
|
|
813
|
+
*
|
|
814
|
+
* Interface for XML parsing, decoupled from any specific parser library.
|
|
815
|
+
* Allows swapping the underlying parser (currently fast-xml-parser)
|
|
816
|
+
* by implementing a single interface. (Goldene Regel 14)
|
|
817
|
+
*/
|
|
818
|
+
/**
|
|
819
|
+
* Parsed XML element with attributes and children.
|
|
820
|
+
*/
|
|
821
|
+
interface XmlElement {
|
|
822
|
+
/** Element tag name */
|
|
823
|
+
tag: string;
|
|
824
|
+
/** Element attributes as key-value pairs */
|
|
825
|
+
attributes: Record<string, string>;
|
|
826
|
+
/** Child elements */
|
|
827
|
+
children: XmlElement[];
|
|
828
|
+
/** Text content (if any) */
|
|
829
|
+
text?: string;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Abstraction for XML parsing. Implementations must convert an XML string
|
|
833
|
+
* into a tree of XmlElement objects.
|
|
834
|
+
*
|
|
835
|
+
* To swap the underlying parser library, implement this interface
|
|
836
|
+
* and pass it to the FormXml parser. Only this file needs to change.
|
|
837
|
+
*/
|
|
838
|
+
interface XmlParser {
|
|
839
|
+
parse(xml: string): XmlElement;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* XML parser implementation using fast-xml-parser.
|
|
843
|
+
* Zero dependencies (fast-xml-parser itself has none), 26 KB minified.
|
|
844
|
+
*/
|
|
845
|
+
declare class FastXmlParser implements XmlParser {
|
|
846
|
+
private readonly parser;
|
|
847
|
+
constructor();
|
|
848
|
+
parse(xml: string): XmlElement;
|
|
849
|
+
private convertToXmlElement;
|
|
850
|
+
private convertNode;
|
|
851
|
+
}
|
|
852
|
+
/** Default parser instance. Use this unless you need a custom parser. */
|
|
853
|
+
declare const defaultXmlParser: XmlParser;
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* @xrmforge/typegen - FormXml Parser
|
|
857
|
+
*
|
|
858
|
+
* Parses Dataverse FormXml into structured TypeScript objects.
|
|
859
|
+
* Extracts tabs, sections, controls (data-bound + special) for generating
|
|
860
|
+
* typed FormContext interfaces with compile-time field validation.
|
|
861
|
+
*
|
|
862
|
+
* Uses the XmlParser abstraction (Goldene Regel 14) instead of regex.
|
|
863
|
+
*/
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Parse a SystemFormMetadata response into a structured ParsedForm.
|
|
867
|
+
*
|
|
868
|
+
* @param form - The system form metadata from the API
|
|
869
|
+
* @param parser - XML parser to use (defaults to fast-xml-parser)
|
|
870
|
+
* @throws {MetadataError} if the formxml cannot be parsed
|
|
871
|
+
*/
|
|
872
|
+
declare function parseForm(form: SystemFormMetadata, parser?: XmlParser): ParsedForm;
|
|
873
|
+
/**
|
|
874
|
+
* Extract all data-bound control field names from FormXml (flattened).
|
|
875
|
+
* Simpler alternative to full parsing when only the field list is needed.
|
|
876
|
+
*/
|
|
877
|
+
declare function extractControlFields(formxml: string, parser?: XmlParser): string[];
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* @xrmforge/typegen - Type Mapping
|
|
881
|
+
*
|
|
882
|
+
* Maps Dataverse AttributeType values to TypeScript types for:
|
|
883
|
+
* 1. Entity interfaces (Web API data types)
|
|
884
|
+
* 2. Form interfaces (Xrm.Attributes.* types from @types/xrm)
|
|
885
|
+
* 3. Control interfaces (Xrm.Controls.* types from @types/xrm)
|
|
886
|
+
*
|
|
887
|
+
* This is the bridge between Dataverse metadata and generated TypeScript.
|
|
888
|
+
* Goldene Regel 1: All types extend @types/xrm, never replace.
|
|
889
|
+
*/
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Map Dataverse AttributeType to TypeScript type for entity interfaces.
|
|
893
|
+
* These represent the raw data types returned by the Web API.
|
|
894
|
+
*
|
|
895
|
+
* @param attributeType - The AttributeType from Dataverse metadata
|
|
896
|
+
* @param isLookup - Whether this is a lookup field (uses _fieldname_value pattern)
|
|
897
|
+
* @returns TypeScript type string (e.g. "string", "number", "boolean")
|
|
898
|
+
*/
|
|
899
|
+
declare function getEntityPropertyType(attributeType: string, isLookup?: boolean): string;
|
|
900
|
+
/**
|
|
901
|
+
* Map Dataverse AttributeType to Xrm.Attributes.* type for form interfaces.
|
|
902
|
+
* These represent the getAttribute() return types on FormContext.
|
|
903
|
+
*
|
|
904
|
+
* @param attributeType - The AttributeType from Dataverse metadata
|
|
905
|
+
* @returns Fully qualified Xrm attribute type string
|
|
906
|
+
*/
|
|
907
|
+
declare function getFormAttributeType(attributeType: string): string;
|
|
908
|
+
/**
|
|
909
|
+
* Map Dataverse AttributeType to Xrm.Controls.* type for form interfaces.
|
|
910
|
+
* These represent the getControl() return types on FormContext.
|
|
911
|
+
*
|
|
912
|
+
* @param attributeType - The AttributeType from Dataverse metadata
|
|
913
|
+
* @returns Fully qualified Xrm control type string
|
|
914
|
+
*/
|
|
915
|
+
declare function getFormControlType(attributeType: string): string;
|
|
916
|
+
/**
|
|
917
|
+
* Convert a Dataverse LogicalName to a safe TypeScript identifier.
|
|
918
|
+
* Validates that the result is a valid identifier.
|
|
919
|
+
*
|
|
920
|
+
* @param logicalName - Dataverse field or entity logical name
|
|
921
|
+
* @returns A valid TypeScript identifier
|
|
922
|
+
* @throws Never throws; returns the input if already valid, prefixes with _ if starts with digit
|
|
923
|
+
*/
|
|
924
|
+
declare function toSafeIdentifier(logicalName: string): string;
|
|
925
|
+
/**
|
|
926
|
+
* Convert a Dataverse LogicalName to PascalCase for use as interface/type name.
|
|
927
|
+
*
|
|
928
|
+
* @example
|
|
929
|
+
* toPascalCase('account') // 'Account'
|
|
930
|
+
* toPascalCase('markant_cdhcontactsource') // 'MarkantCdhcontactsource'
|
|
931
|
+
*/
|
|
932
|
+
declare function toPascalCase(logicalName: string): string;
|
|
933
|
+
/**
|
|
934
|
+
* Convert a lookup attribute LogicalName to its Web API value property name.
|
|
935
|
+
* In the Web API, lookup fields are represented as `_fieldname_value`.
|
|
936
|
+
*
|
|
937
|
+
* @example
|
|
938
|
+
* toLookupValueProperty('primarycontactid') // '_primarycontactid_value'
|
|
939
|
+
* toLookupValueProperty('ownerid') // '_ownerid_value'
|
|
940
|
+
*/
|
|
941
|
+
declare function toLookupValueProperty(logicalName: string): string;
|
|
942
|
+
/**
|
|
943
|
+
* Determine if an attribute is a single-value lookup type.
|
|
944
|
+
* PartyList is NOT included: it's a collection navigation property (ActivityParty[]),
|
|
945
|
+
* not a single _fieldname_value property in the Web API.
|
|
946
|
+
*/
|
|
947
|
+
declare function isLookupType(attributeType: string): boolean;
|
|
948
|
+
/**
|
|
949
|
+
* Determine if an attribute should be included in entity interfaces.
|
|
950
|
+
* Excludes virtual/calculated fields that are not readable via Web API.
|
|
951
|
+
*
|
|
952
|
+
* Filtered types:
|
|
953
|
+
* - Virtual, CalendarRules: not readable via Web API
|
|
954
|
+
* - ManagedProperty: solution metadata (iscustomizable etc.), not business data
|
|
955
|
+
* - EntityName: internal companion fields for lookups; entity type info is only
|
|
956
|
+
* available via @Microsoft.Dynamics.CRM.lookuplogicalname OData annotation,
|
|
957
|
+
* not as a standalone property in Web API responses
|
|
958
|
+
*/
|
|
959
|
+
declare function shouldIncludeInEntityInterface(attr: AttributeMetadata): boolean;
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* @xrmforge/typegen - Generator-specific Label Utilities
|
|
963
|
+
*
|
|
964
|
+
* This module contains ONLY generator-specific label functions.
|
|
965
|
+
* Core label extraction (getPrimaryLabel, getJSDocLabel, LabelConfig etc.)
|
|
966
|
+
* is provided by the canonical implementation in metadata/labels.ts (R6-02).
|
|
967
|
+
*
|
|
968
|
+
* Re-exports from metadata/labels.ts are provided for convenience.
|
|
969
|
+
*/
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Extract the secondary language label, if configured and available.
|
|
973
|
+
* Returns undefined if no secondary language is configured or label not found.
|
|
974
|
+
*/
|
|
975
|
+
declare function getSecondaryLabel(label: Label, config: LabelConfig): string | undefined;
|
|
976
|
+
/**
|
|
977
|
+
* Disambiguate duplicate enum member names by appending the numeric value.
|
|
978
|
+
* Only the second and subsequent duplicates get the suffix.
|
|
979
|
+
* Re-checks that the suffixed name doesn't collide with an existing name.
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* disambiguateEnumMembers([
|
|
983
|
+
* { name: "Active", value: 1 },
|
|
984
|
+
* { name: "Active", value: 2 },
|
|
985
|
+
* ])
|
|
986
|
+
* // [{ name: "Active", value: 1 }, { name: "Active_2", value: 2 }]
|
|
987
|
+
*
|
|
988
|
+
* // Edge case: "Active_2" already exists as a label-derived name
|
|
989
|
+
* disambiguateEnumMembers([
|
|
990
|
+
* { name: "Active", value: 1 },
|
|
991
|
+
* { name: "Active", value: 2 },
|
|
992
|
+
* { name: "Active_2", value: 3 },
|
|
993
|
+
* ])
|
|
994
|
+
* // [{ name: "Active", value: 1 }, { name: "Active_2_v2", value: 2 }, { name: "Active_2", value: 3 }]
|
|
995
|
+
*/
|
|
996
|
+
declare function disambiguateEnumMembers(members: Array<{
|
|
997
|
+
name: string;
|
|
998
|
+
value: number;
|
|
999
|
+
}>): Array<{
|
|
1000
|
+
name: string;
|
|
1001
|
+
value: number;
|
|
1002
|
+
}>;
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* @xrmforge/typegen - Entity Interface Generator
|
|
1006
|
+
*
|
|
1007
|
+
* Generates TypeScript declaration files (.d.ts) for Dataverse entity interfaces.
|
|
1008
|
+
* These interfaces represent the data types returned by the Web API.
|
|
1009
|
+
*
|
|
1010
|
+
* Output pattern:
|
|
1011
|
+
* ```typescript
|
|
1012
|
+
* declare namespace XrmForge.Entities {
|
|
1013
|
+
* interface Account {
|
|
1014
|
+
* accountid: string | null;
|
|
1015
|
+
* name: string | null;
|
|
1016
|
+
* // ...
|
|
1017
|
+
* }
|
|
1018
|
+
* }
|
|
1019
|
+
* ```
|
|
1020
|
+
*/
|
|
1021
|
+
|
|
1022
|
+
/** Options for entity interface generation */
|
|
1023
|
+
interface EntityGeneratorOptions {
|
|
1024
|
+
/** Label configuration for dual-language JSDoc comments */
|
|
1025
|
+
labelConfig?: LabelConfig;
|
|
1026
|
+
/** Namespace for generated types (default: "XrmForge.Entities") */
|
|
1027
|
+
namespace?: string;
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Generate a TypeScript declaration for an entity interface.
|
|
1031
|
+
*
|
|
1032
|
+
* @param info - Complete entity metadata (from MetadataClient.getEntityTypeInfo)
|
|
1033
|
+
* @param options - Generator options
|
|
1034
|
+
* @returns TypeScript declaration string (.d.ts content)
|
|
1035
|
+
*/
|
|
1036
|
+
declare function generateEntityInterface(info: EntityTypeInfo, options?: EntityGeneratorOptions): string;
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* @xrmforge/typegen - OptionSet Enum Generator
|
|
1040
|
+
*
|
|
1041
|
+
* Generates TypeScript const enums from Dataverse OptionSet metadata.
|
|
1042
|
+
* Uses const enum because D365 form scripts have no module system at runtime,
|
|
1043
|
+
* so enum values must be inlined at compile time.
|
|
1044
|
+
*
|
|
1045
|
+
* Output pattern:
|
|
1046
|
+
* ```typescript
|
|
1047
|
+
* declare namespace XrmForge.OptionSets {
|
|
1048
|
+
* const enum AccountCategoryCode {
|
|
1049
|
+
* PreferredCustomer = 1,
|
|
1050
|
+
* Standard = 2,
|
|
1051
|
+
* }
|
|
1052
|
+
* }
|
|
1053
|
+
* ```
|
|
1054
|
+
*/
|
|
1055
|
+
|
|
1056
|
+
/** Options for OptionSet enum generation */
|
|
1057
|
+
interface OptionSetGeneratorOptions {
|
|
1058
|
+
/** Label configuration for dual-language JSDoc comments */
|
|
1059
|
+
labelConfig?: LabelConfig;
|
|
1060
|
+
/** Namespace for generated types (default: "XrmForge.OptionSets") */
|
|
1061
|
+
namespace?: string;
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Generate a TypeScript const enum declaration from an OptionSet.
|
|
1065
|
+
*
|
|
1066
|
+
* @param optionSet - OptionSet metadata from Dataverse
|
|
1067
|
+
* @param entityLogicalName - Entity this OptionSet belongs to (for naming local OptionSets)
|
|
1068
|
+
* @param attributeSchemaName - Attribute schema name (for naming local OptionSets)
|
|
1069
|
+
* @param options - Generator options
|
|
1070
|
+
* @returns TypeScript const enum declaration string
|
|
1071
|
+
*/
|
|
1072
|
+
declare function generateOptionSetEnum(optionSet: OptionSetMetadata, _entityLogicalName: string, attributeSchemaName: string, options?: OptionSetGeneratorOptions): string;
|
|
1073
|
+
/**
|
|
1074
|
+
* Generate multiple OptionSet enums for all picklist attributes of an entity.
|
|
1075
|
+
* Handles both local and global OptionSets.
|
|
1076
|
+
*
|
|
1077
|
+
* @param picklistAttributes - Picklist attributes with their OptionSet metadata
|
|
1078
|
+
* @param entityLogicalName - Entity logical name
|
|
1079
|
+
* @param options - Generator options
|
|
1080
|
+
* @returns Array of { enumName, content } for each generated enum
|
|
1081
|
+
*/
|
|
1082
|
+
declare function generateEntityOptionSets(picklistAttributes: Array<{
|
|
1083
|
+
SchemaName: string;
|
|
1084
|
+
OptionSet: OptionSetMetadata | null;
|
|
1085
|
+
GlobalOptionSet: OptionSetMetadata | null;
|
|
1086
|
+
}>, entityLogicalName: string, options?: OptionSetGeneratorOptions): Array<{
|
|
1087
|
+
enumName: string;
|
|
1088
|
+
content: string;
|
|
1089
|
+
}>;
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* @xrmforge/typegen - Form Interface Generator
|
|
1093
|
+
*
|
|
1094
|
+
* Generates TypeScript form interfaces with compile-time field validation.
|
|
1095
|
+
*
|
|
1096
|
+
* Architecture:
|
|
1097
|
+
* 1. Union Type (LeadFormFields): restricts getAttribute to form-specific fields only
|
|
1098
|
+
* 2. Mapped Return Type (LeadAttributeMap): maps field name to correct Xrm type
|
|
1099
|
+
* 3. Generic getAttribute<K>: returns the exact type for each field
|
|
1100
|
+
* 4. Fields const enum: provides autocomplete with dual-language labels
|
|
1101
|
+
* 5. NO fallback getAttribute(name: string): unknown fields are compile errors
|
|
1102
|
+
*
|
|
1103
|
+
* Output pattern:
|
|
1104
|
+
* ```typescript
|
|
1105
|
+
* declare namespace XrmForge.Forms.Account {
|
|
1106
|
+
* type AccountMainFormFields = "name" | "telephone1" | "revenue";
|
|
1107
|
+
*
|
|
1108
|
+
* type AccountMainFormAttributeMap = {
|
|
1109
|
+
* name: Xrm.Attributes.StringAttribute;
|
|
1110
|
+
* telephone1: Xrm.Attributes.StringAttribute;
|
|
1111
|
+
* revenue: Xrm.Attributes.NumberAttribute;
|
|
1112
|
+
* };
|
|
1113
|
+
*
|
|
1114
|
+
* type AccountMainFormControlMap = {
|
|
1115
|
+
* name: Xrm.Controls.StringControl;
|
|
1116
|
+
* telephone1: Xrm.Controls.StringControl;
|
|
1117
|
+
* revenue: Xrm.Controls.NumberControl;
|
|
1118
|
+
* };
|
|
1119
|
+
*
|
|
1120
|
+
* const enum AccountMainFormFields {
|
|
1121
|
+
* Name = 'name',
|
|
1122
|
+
* Telephone1 = 'telephone1',
|
|
1123
|
+
* Revenue = 'revenue',
|
|
1124
|
+
* }
|
|
1125
|
+
*
|
|
1126
|
+
* interface AccountMainForm extends Omit<Xrm.FormContext, 'getAttribute' | 'getControl'> {
|
|
1127
|
+
* getAttribute<K extends AccountMainFormFields>(name: K): AccountMainFormAttributeMap[K];
|
|
1128
|
+
* getAttribute(index: number): Xrm.Attributes.Attribute;
|
|
1129
|
+
* getAttribute(): Xrm.Attributes.Attribute[];
|
|
1130
|
+
* getControl<K extends AccountMainFormFields>(name: K): AccountMainFormControlMap[K];
|
|
1131
|
+
* getControl(index: number): Xrm.Controls.Control;
|
|
1132
|
+
* getControl(): Xrm.Controls.Control[];
|
|
1133
|
+
* }
|
|
1134
|
+
* }
|
|
1135
|
+
* ```
|
|
1136
|
+
*/
|
|
1137
|
+
|
|
1138
|
+
/** Options for form interface generation */
|
|
1139
|
+
interface FormGeneratorOptions {
|
|
1140
|
+
/** Label configuration for dual-language JSDoc comments */
|
|
1141
|
+
labelConfig?: LabelConfig;
|
|
1142
|
+
/** Namespace prefix for generated types (default: "XrmForge.Forms") */
|
|
1143
|
+
namespacePrefix?: string;
|
|
1144
|
+
/** Form types to include (default: [2] = Main only) */
|
|
1145
|
+
formTypes?: number[];
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Generate a complete form declaration: union type, mapped types, fields enum, and interface.
|
|
1149
|
+
*
|
|
1150
|
+
* @param form - Parsed form structure (from FormXml parser)
|
|
1151
|
+
* @param entityLogicalName - Entity this form belongs to
|
|
1152
|
+
* @param attributeMap - Map of LogicalName to AttributeMetadata for type resolution
|
|
1153
|
+
* @param options - Generator options
|
|
1154
|
+
* @returns TypeScript declaration string
|
|
1155
|
+
*/
|
|
1156
|
+
declare function generateFormInterface(form: ParsedForm, entityLogicalName: string, attributeMap: Map<string, AttributeMetadata>, options?: FormGeneratorOptions, baseNameOverride?: string): string;
|
|
1157
|
+
/**
|
|
1158
|
+
* Generate form interfaces for all forms of an entity.
|
|
1159
|
+
*
|
|
1160
|
+
* @param forms - Parsed forms (from FormXml parser)
|
|
1161
|
+
* @param entityLogicalName - Entity logical name
|
|
1162
|
+
* @param attributes - All attributes of the entity (for type resolution)
|
|
1163
|
+
* @param options - Generator options
|
|
1164
|
+
* @returns Array of { formName, interfaceName, content }
|
|
1165
|
+
*/
|
|
1166
|
+
declare function generateEntityForms(forms: ParsedForm[], entityLogicalName: string, attributes: AttributeMetadata[], options?: FormGeneratorOptions): Array<{
|
|
1167
|
+
formName: string;
|
|
1168
|
+
interfaceName: string;
|
|
1169
|
+
content: string;
|
|
1170
|
+
}>;
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* @xrmforge/typegen - Orchestrator Types
|
|
1174
|
+
*
|
|
1175
|
+
* Configuration and result types for the type generation orchestrator.
|
|
1176
|
+
*/
|
|
1177
|
+
|
|
1178
|
+
/** Configuration for the type generation process */
|
|
1179
|
+
interface GenerateConfig {
|
|
1180
|
+
/** Dataverse environment URL (e.g. "https://myorg.crm4.dynamics.com") */
|
|
1181
|
+
environmentUrl: string;
|
|
1182
|
+
/** Entity logical names to generate types for (merged with solution entities if both set) */
|
|
1183
|
+
entities: string[];
|
|
1184
|
+
/** Solution unique names to discover entities automatically (merged with entities, deduplicated) */
|
|
1185
|
+
solutionNames?: string[];
|
|
1186
|
+
/** Output directory for generated .d.ts files */
|
|
1187
|
+
outputDir: string;
|
|
1188
|
+
/** Label language configuration */
|
|
1189
|
+
labelConfig: LabelConfig;
|
|
1190
|
+
/** Whether to generate entity interfaces (default: true) */
|
|
1191
|
+
generateEntities?: boolean;
|
|
1192
|
+
/** Whether to generate form interfaces (default: true) */
|
|
1193
|
+
generateForms?: boolean;
|
|
1194
|
+
/** Whether to generate OptionSet enums (default: true) */
|
|
1195
|
+
generateOptionSets?: boolean;
|
|
1196
|
+
/**
|
|
1197
|
+
* Whether to use metadata cache for faster re-generation.
|
|
1198
|
+
* @alpha Not yet implemented. Setting this to true will throw a ConfigError.
|
|
1199
|
+
* Planned for v0.2.0.
|
|
1200
|
+
* @defaultValue false
|
|
1201
|
+
*/
|
|
1202
|
+
useCache?: boolean;
|
|
1203
|
+
/**
|
|
1204
|
+
* Cache directory for metadata cache.
|
|
1205
|
+
* @alpha Not yet implemented. Ignored until useCache is implemented.
|
|
1206
|
+
* Planned for v0.2.0.
|
|
1207
|
+
* @defaultValue ".xrmforge/cache"
|
|
1208
|
+
*/
|
|
1209
|
+
cacheDir?: string;
|
|
1210
|
+
/** XrmForge namespace prefix (default: "XrmForge") */
|
|
1211
|
+
namespacePrefix?: string;
|
|
1212
|
+
}
|
|
1213
|
+
/** Result of generating types for a single entity */
|
|
1214
|
+
interface EntityGenerationResult {
|
|
1215
|
+
/** Entity logical name */
|
|
1216
|
+
entityLogicalName: string;
|
|
1217
|
+
/** Files written */
|
|
1218
|
+
files: GeneratedFile[];
|
|
1219
|
+
/** Warnings (e.g. missing labels, empty forms) */
|
|
1220
|
+
warnings: string[];
|
|
1221
|
+
}
|
|
1222
|
+
/** A single generated file */
|
|
1223
|
+
interface GeneratedFile {
|
|
1224
|
+
/** Relative path from outputDir */
|
|
1225
|
+
relativePath: string;
|
|
1226
|
+
/** File content */
|
|
1227
|
+
content: string;
|
|
1228
|
+
/** Type of generated content */
|
|
1229
|
+
type: 'entity' | 'optionset' | 'form';
|
|
1230
|
+
}
|
|
1231
|
+
/** Overall result of the generation process */
|
|
1232
|
+
interface GenerationResult {
|
|
1233
|
+
/** Per-entity results */
|
|
1234
|
+
entities: EntityGenerationResult[];
|
|
1235
|
+
/** Total files written */
|
|
1236
|
+
totalFiles: number;
|
|
1237
|
+
/** Total warnings */
|
|
1238
|
+
totalWarnings: number;
|
|
1239
|
+
/** Duration in milliseconds */
|
|
1240
|
+
durationMs: number;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* @xrmforge/typegen - Type Generation Orchestrator
|
|
1245
|
+
*
|
|
1246
|
+
* Coordinates the full type generation pipeline:
|
|
1247
|
+
* 1. Fetch metadata for requested entities (via MetadataClient)
|
|
1248
|
+
* 2. Generate entity interfaces, OptionSet enums, form interfaces
|
|
1249
|
+
* 3. Write .d.ts files to disk
|
|
1250
|
+
*
|
|
1251
|
+
* This is the main entry point that ties all components together.
|
|
1252
|
+
*/
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Main orchestrator for type generation.
|
|
1256
|
+
*
|
|
1257
|
+
* Usage:
|
|
1258
|
+
* ```typescript
|
|
1259
|
+
* const orchestrator = new TypeGenerationOrchestrator(credential, {
|
|
1260
|
+
* environmentUrl: 'https://myorg.crm4.dynamics.com',
|
|
1261
|
+
* entities: ['account', 'contact'],
|
|
1262
|
+
* outputDir: './typings',
|
|
1263
|
+
* labelConfig: { primaryLanguage: 1033, secondaryLanguage: 1031 },
|
|
1264
|
+
* });
|
|
1265
|
+
* const result = await orchestrator.generate();
|
|
1266
|
+
* ```
|
|
1267
|
+
*/
|
|
1268
|
+
declare class TypeGenerationOrchestrator {
|
|
1269
|
+
private readonly config;
|
|
1270
|
+
private readonly credential;
|
|
1271
|
+
private readonly logger;
|
|
1272
|
+
constructor(credential: TokenCredential, config: GenerateConfig, logger?: Logger);
|
|
1273
|
+
/**
|
|
1274
|
+
* Run the full type generation pipeline.
|
|
1275
|
+
*
|
|
1276
|
+
* @param options - Optional parameters
|
|
1277
|
+
* @param options.signal - AbortSignal to cancel the generation process.
|
|
1278
|
+
* When aborted, entities that have not yet started processing are skipped.
|
|
1279
|
+
* Entities already in progress may still complete or fail with an abort error.
|
|
1280
|
+
*/
|
|
1281
|
+
generate(options?: {
|
|
1282
|
+
signal?: AbortSignal;
|
|
1283
|
+
}): Promise<GenerationResult>;
|
|
1284
|
+
/**
|
|
1285
|
+
* Process a single entity: fetch metadata, generate all output files.
|
|
1286
|
+
*/
|
|
1287
|
+
private processEntity;
|
|
1288
|
+
/**
|
|
1289
|
+
* Extract picklist attributes with their OptionSet metadata.
|
|
1290
|
+
* Maps the raw EntityTypeInfo data to the format expected by the OptionSet generator.
|
|
1291
|
+
*/
|
|
1292
|
+
private getPicklistAttributes;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
export { ApiRequestError, type AttributeMetadata, type AuthConfig, type AuthMethod, AuthenticationError, type ClientCredentialsAuth, ConfigError, ConsoleLogSink, DEFAULT_LABEL_CONFIG, DataverseHttpClient, type DateTimeAttributeMetadata, type DecimalAttributeMetadata, type DeviceCodeAuth, type EntityGenerationResult, type EntityGeneratorOptions, type EntityMetadata, type EntityTypeInfo, ErrorCode, FastXmlParser, type FormControl, type FormGeneratorOptions, type FormSection, type FormTab, type GenerateConfig, type GeneratedFile, GenerationError, type GenerationResult, type HttpClientOptions, type IntegerAttributeMetadata, type InteractiveAuth, JsonLogSink, type Label, type LabelConfig, type LocalizedLabel, type LogEntry, LogLevel, type LogSink, Logger, type LookupAttributeMetadata, type ManyToManyRelationshipMetadata, MetadataCache, MetadataClient, MetadataError, type MoneyAttributeMetadata, type OneToManyRelationshipMetadata, type OptionMetadata, type OptionSetGeneratorOptions, type OptionSetMetadata, type ParsedForm, type PicklistAttributeMetadata, SilentLogSink, type SolutionComponent, type StateAttributeMetadata, type StatusAttributeMetadata, type StringAttributeMetadata, type SystemFormMetadata, TypeGenerationOrchestrator, type XmlElement, type XmlParser, XrmForgeError, configureLogging, createCredential, createLogger, defaultXmlParser, disambiguateEnumMembers, extractControlFields, getJSDocLabel as formatDualLabel, generateEntityForms, generateEntityInterface, generateEntityOptionSets, generateEnumMembers, generateFormInterface, generateOptionSetEnum, getEntityPropertyType, getFormAttributeType, getFormControlType, getJSDocLabel, getLabelLanguagesParam, getPrimaryLabel, getSecondaryLabel, isLookupType, isRateLimitError, isXrmForgeError, labelToIdentifier, parseForm, shouldIncludeInEntityInterface, toLookupValueProperty, toPascalCase, toSafeIdentifier };
|