@xrmforge/typegen 0.7.1 → 0.8.1
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/MIGRATION.md +40 -11
- package/dist/index.d.ts +15 -27
- package/dist/index.js +222 -212
- package/dist/index.js.map +1 -1
- package/docs/architecture/02-packages.md +1 -1
- package/docs/architecture/03-generated-types.md +86 -90
- package/docs/architecture/04-cli.md +2 -2
- package/docs/architecture/09-testing.md +1 -1
- package/docs/architecture/10-eslint-plugin.md +1 -1
- package/docs/architecture/11-agent-md.md +1 -1
- package/docs/architecture/12-xrm-pitfalls.md +1 -1
- package/docs/architecture/16-technical-debt.md +1 -1
- package/docs/architektur/02-packages.md +1 -1
- package/docs/architektur/03-generierte-typen.md +86 -90
- package/docs/architektur/04-cli.md +2 -2
- package/docs/architektur/09-testing.md +1 -1
- package/docs/architektur/10-eslint-plugin.md +1 -1
- package/docs/architektur/11-agent-md.md +1 -1
- package/docs/architektur/12-xrm-fallstricke.md +1 -1
- package/docs/architektur/16-technische-schulden.md +1 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| Package | Version | Tests | Description |
|
|
6
6
|
|---------|---------|-------|-------------|
|
|
7
|
-
| @xrmforge/typegen | 0.
|
|
7
|
+
| @xrmforge/typegen | 0.8.0 | 444 | Core: type generation engine, metadata client, HTTP client, helpers |
|
|
8
8
|
| @xrmforge/cli | 0.4.2 | 10 | CLI: generate, build, init commands |
|
|
9
9
|
| @xrmforge/testing | 0.2.0 | 76 | Test utilities: createFormMock, fireOnChange, setupXrmMock |
|
|
10
10
|
| @xrmforge/helpers | 0.1.0 | 59 | Browser-safe runtime: select(), parseLookup(), typedForm(), Xrm constants, Action executors |
|
|
@@ -1,91 +1,93 @@
|
|
|
1
1
|
# Generated Types
|
|
2
2
|
|
|
3
|
-
Running `xrmforge generate` produces the following TypeScript
|
|
3
|
+
Running `xrmforge generate` produces the following TypeScript ES modules:
|
|
4
4
|
|
|
5
|
-
### 3.1 Entity Interfaces (`entities/{entity}.
|
|
5
|
+
### 3.1 Entity Interfaces (`entities/{entity}.ts`)
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
8
|
+
// generated/entities/account.ts
|
|
9
|
+
/** Account | Konto */
|
|
10
|
+
export interface Account {
|
|
11
|
+
/** Account Name | Kontoname */
|
|
12
|
+
name: string | null;
|
|
13
|
+
accountid: string | null;
|
|
14
|
+
revenue: number | null;
|
|
15
|
+
_parentaccountid_value: string | null; // Lookup GUID
|
|
16
|
+
// ...
|
|
18
17
|
}
|
|
19
18
|
```
|
|
20
19
|
|
|
21
20
|
**Type mapping:** String/Memo/EntityName to `string`, Integer/BigInt/Decimal/Double/Money to `number`, Boolean to `boolean`, DateTime/Uniqueidentifier/Lookup to `string`, Picklist/State/Status to `number`.
|
|
22
21
|
|
|
23
|
-
### 3.2 Entity Fields Enums (`
|
|
22
|
+
### 3.2 Entity Fields Enums (`fields/{entity}.ts`)
|
|
24
23
|
|
|
25
24
|
```typescript
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
// generated/fields/account.ts
|
|
26
|
+
export const enum AccountFields {
|
|
27
|
+
/** Account Name | Kontoname */
|
|
28
|
+
Name = 'name',
|
|
29
|
+
Telephone1 = 'telephone1',
|
|
30
|
+
Revenue = 'revenue',
|
|
31
|
+
// all entity attributes for $select queries
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const enum AccountNavigationProperties {
|
|
35
|
+
PrimaryContact = 'primarycontactid',
|
|
36
|
+
ContactCustomerAccounts = 'contact_customer_accounts',
|
|
37
|
+
// all lookup navigation properties
|
|
33
38
|
}
|
|
34
39
|
```
|
|
35
40
|
|
|
36
41
|
Used for Web API `$select`: `select(AccountFields.Name, AccountFields.Revenue)`.
|
|
37
42
|
|
|
38
|
-
### 3.3 Navigation Properties (`
|
|
43
|
+
### 3.3 Navigation Properties (`fields/{entity}.ts`)
|
|
44
|
+
|
|
45
|
+
Navigation property enums are co-located with the Fields enums in the same file (see 3.2 above). Example usage:
|
|
39
46
|
|
|
40
47
|
```typescript
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
PrimaryContactId = 'primarycontactid',
|
|
44
|
-
ContactCustomerAccounts = 'contact_customer_accounts',
|
|
45
|
-
// OneToMany + ManyToMany relationships
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
+
import { AccountNavigationProperties } from '../generated/fields/account';
|
|
49
|
+
// used for $expand queries
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
### 3.4 Form Interfaces (`forms/{entity}.
|
|
52
|
+
### 3.4 Form Interfaces (`forms/{entity}.ts`)
|
|
51
53
|
|
|
52
54
|
```typescript
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
55
|
+
// generated/forms/account.ts
|
|
56
|
+
|
|
57
|
+
// Union type restricting valid field names
|
|
58
|
+
export type AccountMainFormFields = 'name' | 'telephone1' | 'revenue';
|
|
59
|
+
|
|
60
|
+
// Mapped type: field name to Xrm attribute type
|
|
61
|
+
export type AccountMainFormAttributeMap = {
|
|
62
|
+
name: Xrm.Attributes.StringAttribute;
|
|
63
|
+
telephone1: Xrm.Attributes.StringAttribute;
|
|
64
|
+
revenue: Xrm.Attributes.NumberAttribute;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Mapped type: field name to Xrm control type
|
|
68
|
+
export type AccountMainFormControlMap = {
|
|
69
|
+
name: Xrm.Controls.StringControl;
|
|
70
|
+
telephone1: Xrm.Controls.StringControl;
|
|
71
|
+
revenue: Xrm.Controls.NumberControl;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Fields enum for autocomplete
|
|
75
|
+
export const enum AccountMainFormFieldsEnum {
|
|
76
|
+
/** Account Name | Kontoname */
|
|
77
|
+
AccountName = 'name',
|
|
78
|
+
Telephone1 = 'telephone1',
|
|
79
|
+
Revenue = 'revenue',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Type-safe FormContext with overloaded getAttribute/getControl
|
|
83
|
+
export interface AccountMainForm extends Omit<Xrm.FormContext, 'getAttribute' | 'getControl'> {
|
|
84
|
+
getAttribute<K extends AccountMainFormFields>(name: K): AccountMainFormAttributeMap[K];
|
|
85
|
+
getAttribute(index: number): Xrm.Attributes.Attribute;
|
|
86
|
+
getAttribute(): Xrm.Attributes.Attribute[];
|
|
87
|
+
|
|
88
|
+
getControl<K extends AccountMainFormFields>(name: K): AccountMainFormControlMap[K];
|
|
89
|
+
getControl(index: number): Xrm.Controls.Control;
|
|
90
|
+
getControl(): Xrm.Controls.Control[];
|
|
89
91
|
}
|
|
90
92
|
```
|
|
91
93
|
|
|
@@ -104,30 +106,28 @@ const enum AccountMainFormSubgrids { Contacts = 'Contacts_Subgrid' }
|
|
|
104
106
|
const enum AccountMainFormQuickViews { ContactPreview = 'ContactQuickView' }
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
### 3.6 OptionSet Enums (`optionsets/{entity}.
|
|
109
|
+
### 3.6 OptionSet Enums (`optionsets/{entity}.ts`)
|
|
108
110
|
|
|
109
111
|
```typescript
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
112
|
+
// generated/optionsets/account.ts
|
|
113
|
+
/** Account Category Code | Kontokategoriecode */
|
|
114
|
+
export const enum AccountCategoryCode {
|
|
115
|
+
/** Preferred Customer | Bevorzugter Kunde */
|
|
116
|
+
PreferredCustomer = 1,
|
|
117
|
+
Standard = 2,
|
|
117
118
|
}
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
Includes Picklist, Status, State, and MultiSelectPicklist attributes. Duplicate labels are disambiguated with `_{Value}` suffix.
|
|
121
122
|
|
|
122
|
-
### 3.7 EntityNames Enum (`entity-names.
|
|
123
|
+
### 3.7 EntityNames Enum (`entity-names.ts`)
|
|
123
124
|
|
|
124
125
|
```typescript
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
126
|
+
// generated/entity-names.ts
|
|
127
|
+
export const enum EntityNames {
|
|
128
|
+
Account = 'account',
|
|
129
|
+
Contact = 'contact',
|
|
130
|
+
// all entities in scope
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
@@ -143,19 +143,15 @@ type AccountMainFormMockValues = {
|
|
|
143
143
|
|
|
144
144
|
Used with `createFormMock<AccountMainForm, AccountMainFormMockValues>({ name: 'Test' })`.
|
|
145
145
|
|
|
146
|
-
### 3.9 Action/Function Executors (`actions/{entity|global}.
|
|
146
|
+
### 3.9 Action/Function Executors (`actions/{entity|global}.ts`)
|
|
147
147
|
|
|
148
|
-
**Declaration (.d.ts):**
|
|
149
148
|
```typescript
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
149
|
+
// generated/actions/global.ts
|
|
150
|
+
import { createUnboundAction } from '@xrmforge/helpers';
|
|
151
|
+
|
|
152
|
+
export interface NormalizePhoneParams { Input: string; AllowSuspicious?: boolean; }
|
|
153
|
+
export interface NormalizePhoneResult { Normalized: string; Status: number; }
|
|
155
154
|
|
|
156
|
-
**Runtime module (.ts):**
|
|
157
|
-
```typescript
|
|
158
|
-
import { createUnboundAction } from '@xrmforge/typegen';
|
|
159
155
|
export const NormalizePhone = createUnboundAction<NormalizePhoneParams, NormalizePhoneResult>(
|
|
160
156
|
'markant_NormalizePhone',
|
|
161
157
|
{ Input: { typeName: 'String', structuralProperty: 1 } }
|
|
@@ -14,7 +14,7 @@ Generates TypeScript declarations from a Dataverse environment.
|
|
|
14
14
|
| `--token <token>` | string | varies | Pre-acquired bearer token (token auth only) |
|
|
15
15
|
| `--entities <list>` | string | - | Comma-separated entity logical names |
|
|
16
16
|
| `--solutions <list>` | string | - | Comma-separated solution unique names |
|
|
17
|
-
| `--output <dir>` | string | ./
|
|
17
|
+
| `--output <dir>` | string | ./generated | Output directory |
|
|
18
18
|
| `--label-language <n>` | string | 1033 | Primary label language (LCID) |
|
|
19
19
|
| `--secondary-language <n>` | string | - | Secondary label language for JSDoc |
|
|
20
20
|
| `--no-forms` | flag | - | Skip form interface generation |
|
|
@@ -55,4 +55,4 @@ Scaffolds a new D365 form scripting project.
|
|
|
55
55
|
| `--skip-install` | flag | false | Skip npm install |
|
|
56
56
|
| `--force` | flag | false | Allow non-empty directories |
|
|
57
57
|
|
|
58
|
-
Generates 11 files: package.json, tsconfig.json, xrmforge.config.json, vitest.config.ts, .gitignore, AGENT.md, example-form.ts, example-form.test.ts,
|
|
58
|
+
Generates 11 files: package.json, tsconfig.json, xrmforge.config.json, vitest.config.ts, .gitignore, AGENT.md, example-form.ts, example-form.test.ts, generated/.gitkeep, GitHub Actions CI, Azure DevOps Pipeline.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { createFormMock } from '@xrmforge/testing';
|
|
7
|
-
import type { AccountMainForm, AccountMainFormMockValues } from '../
|
|
7
|
+
import type { AccountMainForm, AccountMainFormMockValues } from '../generated/forms/account';
|
|
8
8
|
|
|
9
9
|
const mock = createFormMock<AccountMainForm, AccountMainFormMockValues>({
|
|
10
10
|
name: 'Contoso Ltd',
|
|
@@ -36,7 +36,7 @@ Forbids raw numbers (>= 2) in comparisons with `.getValue()`.
|
|
|
36
36
|
if (attr.getValue() === 595300000) { }
|
|
37
37
|
|
|
38
38
|
// Good
|
|
39
|
-
import { StatusCode } from '../
|
|
39
|
+
import { StatusCode } from '../generated/optionsets/account';
|
|
40
40
|
if (attr.getValue() === StatusCode.Active) { }
|
|
41
41
|
```
|
|
42
42
|
|
|
@@ -35,4 +35,4 @@ Five AI models were tested converting legacy D365 JavaScript (account.js + lm_he
|
|
|
35
35
|
|
|
36
36
|
**Criteria (11, max 5 points each = 55 max):** Fields Enum usage, OptionSet Enums, FormContext typing, XrmForge helpers, module exports, tests present, test quality, error handling, code quality, bugs found, documentation.
|
|
37
37
|
|
|
38
|
-
**Key finding:** No AI consistently used `@xrmforge/
|
|
38
|
+
**Key finding:** No AI consistently used `@xrmforge/helpers` imports (select, parseLookup). This remains the biggest adoption gap.
|
|
@@ -10,5 +10,5 @@ Known issues when working with `@types/xrm`:
|
|
|
10
10
|
| setNotification | `setNotification(message)` | `setNotification(message, uniqueId)` (requires 2 args) |
|
|
11
11
|
| openFile | `openFile({ fileName, ... })` | Must include `fileSize` property in FileDetails |
|
|
12
12
|
| SubmitMode | `Xrm.Attributes.SubmitMode` | `Xrm.SubmitMode` |
|
|
13
|
-
| const enum in .d.ts | `const enum` in `.d.ts` files | Use
|
|
13
|
+
| const enum in .d.ts | `const enum` in `.d.ts` files | Use `const enum` in `.ts` ES modules (typegen 0.8.0+ generates `.ts` files, resolving this issue) |
|
|
14
14
|
| Grid.refresh() | `grid.refresh()` | `(grid as any).refresh()` (not typed in @types/xrm) |
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
### 16.2 Accepted Limitations
|
|
14
14
|
|
|
15
|
-
- **const enum limitation:**
|
|
15
|
+
- **const enum limitation:** Resolved in typegen 0.8.0. Generated output is now `.ts` ES modules, so `const enum` works directly with vitest and other test frameworks.
|
|
16
16
|
- **Grid.refresh() requires `as any`:** Not typed in @types/xrm.
|
|
17
17
|
- **Single solution per entity:** If an entity appears in multiple solutions, it is only generated once.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| Package | Version | Tests | Beschreibung |
|
|
6
6
|
|---------|---------|-------|--------------|
|
|
7
|
-
| @xrmforge/typegen | 0.
|
|
7
|
+
| @xrmforge/typegen | 0.8.0 | 444 | Kern: Typgenerierungs-Engine, Metadaten-Client, HTTP-Client, Hilfsfunktionen |
|
|
8
8
|
| @xrmforge/cli | 0.4.2 | 10 | CLI: generate-, build-, init-Befehle |
|
|
9
9
|
| @xrmforge/testing | 0.2.0 | 76 | Test-Hilfsmittel: createFormMock, fireOnChange, setupXrmMock |
|
|
10
10
|
| @xrmforge/helpers | 0.1.0 | 59 | Browsersichere Laufzeit: select(), parseLookup(), typedForm(), Xrm-Konstanten, Action-Executors |
|
|
@@ -1,91 +1,93 @@
|
|
|
1
1
|
# 3. Generierte Typen
|
|
2
2
|
|
|
3
|
-
Die Ausführung von `xrmforge generate` erzeugt die folgenden TypeScript-
|
|
3
|
+
Die Ausführung von `xrmforge generate` erzeugt die folgenden TypeScript-ES-Module:
|
|
4
4
|
|
|
5
|
-
## 3.1 Entitäts-Interfaces (`entities/{entity}.
|
|
5
|
+
## 3.1 Entitäts-Interfaces (`entities/{entity}.ts`)
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
8
|
+
// generated/entities/account.ts
|
|
9
|
+
/** Account | Konto */
|
|
10
|
+
export interface Account {
|
|
11
|
+
/** Account Name | Kontoname */
|
|
12
|
+
name: string | null;
|
|
13
|
+
accountid: string | null;
|
|
14
|
+
revenue: number | null;
|
|
15
|
+
_parentaccountid_value: string | null; // Lookup GUID
|
|
16
|
+
// ...
|
|
18
17
|
}
|
|
19
18
|
```
|
|
20
19
|
|
|
21
20
|
**Typ-Zuordnung:** String/Memo/EntityName zu `string`, Integer/BigInt/Decimal/Double/Money zu `number`, Boolean zu `boolean`, DateTime/Uniqueidentifier/Lookup zu `string`, Picklist/State/Status zu `number`.
|
|
22
21
|
|
|
23
|
-
## 3.2 Entity Fields Enums (`
|
|
22
|
+
## 3.2 Entity Fields Enums (`fields/{entity}.ts`)
|
|
24
23
|
|
|
25
24
|
```typescript
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
// generated/fields/account.ts
|
|
26
|
+
export const enum AccountFields {
|
|
27
|
+
/** Account Name | Kontoname */
|
|
28
|
+
Name = 'name',
|
|
29
|
+
Telephone1 = 'telephone1',
|
|
30
|
+
Revenue = 'revenue',
|
|
31
|
+
// alle Entitätsattribute für $select-Abfragen
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const enum AccountNavigationProperties {
|
|
35
|
+
PrimaryContact = 'primarycontactid',
|
|
36
|
+
ContactCustomerAccounts = 'contact_customer_accounts',
|
|
37
|
+
// alle Lookup-Navigations-Properties
|
|
33
38
|
}
|
|
34
39
|
```
|
|
35
40
|
|
|
36
41
|
Verwendet für Web API `$select`: `select(AccountFields.Name, AccountFields.Revenue)`.
|
|
37
42
|
|
|
38
|
-
## 3.3 Navigations-Properties (`
|
|
43
|
+
## 3.3 Navigations-Properties (`fields/{entity}.ts`)
|
|
44
|
+
|
|
45
|
+
Navigations-Property-Enums befinden sich zusammen mit den Fields-Enums in derselben Datei (siehe 3.2 oben). Beispielverwendung:
|
|
39
46
|
|
|
40
47
|
```typescript
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
PrimaryContactId = 'primarycontactid',
|
|
44
|
-
ContactCustomerAccounts = 'contact_customer_accounts',
|
|
45
|
-
// OneToMany- + ManyToMany-Beziehungen
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
+
import { AccountNavigationProperties } from '../generated/fields/account';
|
|
49
|
+
// verwendet für $expand-Abfragen
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
## 3.4 Formular-Interfaces (`forms/{entity}.
|
|
52
|
+
## 3.4 Formular-Interfaces (`forms/{entity}.ts`)
|
|
51
53
|
|
|
52
54
|
```typescript
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
55
|
+
// generated/forms/account.ts
|
|
56
|
+
|
|
57
|
+
// Union-Typ, der gültige Feldnamen einschränkt
|
|
58
|
+
export type AccountMainFormFields = 'name' | 'telephone1' | 'revenue';
|
|
59
|
+
|
|
60
|
+
// Gemappter Typ: Feldname zu Xrm-Attributtyp
|
|
61
|
+
export type AccountMainFormAttributeMap = {
|
|
62
|
+
name: Xrm.Attributes.StringAttribute;
|
|
63
|
+
telephone1: Xrm.Attributes.StringAttribute;
|
|
64
|
+
revenue: Xrm.Attributes.NumberAttribute;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Gemappter Typ: Feldname zu Xrm-Steuerelementtyp
|
|
68
|
+
export type AccountMainFormControlMap = {
|
|
69
|
+
name: Xrm.Controls.StringControl;
|
|
70
|
+
telephone1: Xrm.Controls.StringControl;
|
|
71
|
+
revenue: Xrm.Controls.NumberControl;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Fields-Enum für Autovervollständigung
|
|
75
|
+
export const enum AccountMainFormFieldsEnum {
|
|
76
|
+
/** Account Name | Kontoname */
|
|
77
|
+
AccountName = 'name',
|
|
78
|
+
Telephone1 = 'telephone1',
|
|
79
|
+
Revenue = 'revenue',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Typsicherer FormContext mit überladenen getAttribute/getControl
|
|
83
|
+
export interface AccountMainForm extends Omit<Xrm.FormContext, 'getAttribute' | 'getControl'> {
|
|
84
|
+
getAttribute<K extends AccountMainFormFields>(name: K): AccountMainFormAttributeMap[K];
|
|
85
|
+
getAttribute(index: number): Xrm.Attributes.Attribute;
|
|
86
|
+
getAttribute(): Xrm.Attributes.Attribute[];
|
|
87
|
+
|
|
88
|
+
getControl<K extends AccountMainFormFields>(name: K): AccountMainFormControlMap[K];
|
|
89
|
+
getControl(index: number): Xrm.Controls.Control;
|
|
90
|
+
getControl(): Xrm.Controls.Control[];
|
|
89
91
|
}
|
|
90
92
|
```
|
|
91
93
|
|
|
@@ -104,30 +106,28 @@ const enum AccountMainFormSubgrids { Contacts = 'Contacts_Subgrid' }
|
|
|
104
106
|
const enum AccountMainFormQuickViews { ContactPreview = 'ContactQuickView' }
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
## 3.6 OptionSet Enums (`optionsets/{entity}.
|
|
109
|
+
## 3.6 OptionSet Enums (`optionsets/{entity}.ts`)
|
|
108
110
|
|
|
109
111
|
```typescript
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
112
|
+
// generated/optionsets/account.ts
|
|
113
|
+
/** Account Category Code | Kontokategoriecode */
|
|
114
|
+
export const enum AccountCategoryCode {
|
|
115
|
+
/** Preferred Customer | Bevorzugter Kunde */
|
|
116
|
+
PreferredCustomer = 1,
|
|
117
|
+
Standard = 2,
|
|
117
118
|
}
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
Umfasst Picklist-, Status-, State- und MultiSelectPicklist-Attribute. Doppelte Labels werden mit dem Suffix `_{Value}` disambiguiert.
|
|
121
122
|
|
|
122
|
-
## 3.7 EntityNames Enum (`entity-names.
|
|
123
|
+
## 3.7 EntityNames Enum (`entity-names.ts`)
|
|
123
124
|
|
|
124
125
|
```typescript
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
126
|
+
// generated/entity-names.ts
|
|
127
|
+
export const enum EntityNames {
|
|
128
|
+
Account = 'account',
|
|
129
|
+
Contact = 'contact',
|
|
130
|
+
// alle Entitäten im Scope
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
@@ -143,19 +143,15 @@ type AccountMainFormMockValues = {
|
|
|
143
143
|
|
|
144
144
|
Verwendet mit `createFormMock<AccountMainForm, AccountMainFormMockValues>({ name: 'Test' })`.
|
|
145
145
|
|
|
146
|
-
## 3.9 Action/Function Executors (`actions/{entity|global}.
|
|
146
|
+
## 3.9 Action/Function Executors (`actions/{entity|global}.ts`)
|
|
147
147
|
|
|
148
|
-
**Deklaration (.d.ts):**
|
|
149
148
|
```typescript
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
149
|
+
// generated/actions/global.ts
|
|
150
|
+
import { createUnboundAction } from '@xrmforge/helpers';
|
|
151
|
+
|
|
152
|
+
export interface NormalizePhoneParams { Input: string; AllowSuspicious?: boolean; }
|
|
153
|
+
export interface NormalizePhoneResult { Normalized: string; Status: number; }
|
|
155
154
|
|
|
156
|
-
**Laufzeitmodul (.ts):**
|
|
157
|
-
```typescript
|
|
158
|
-
import { createUnboundAction } from '@xrmforge/typegen';
|
|
159
155
|
export const NormalizePhone = createUnboundAction<NormalizePhoneParams, NormalizePhoneResult>(
|
|
160
156
|
'markant_NormalizePhone',
|
|
161
157
|
{ Input: { typeName: 'String', structuralProperty: 1 } }
|
|
@@ -14,7 +14,7 @@ Generiert TypeScript-Deklarationen aus einer Dataverse-Umgebung.
|
|
|
14
14
|
| `--token <token>` | string | variiert | Vorab erworbenes Bearer-Token (nur Token-Auth) |
|
|
15
15
|
| `--entities <list>` | string | - | Kommagetrennte logische Entitätsnamen |
|
|
16
16
|
| `--solutions <list>` | string | - | Kommagetrennte eindeutige Lösungsnamen |
|
|
17
|
-
| `--output <dir>` | string | ./
|
|
17
|
+
| `--output <dir>` | string | ./generated | Ausgabeverzeichnis |
|
|
18
18
|
| `--label-language <n>` | string | 1033 | Primäre Label-Sprache (LCID) |
|
|
19
19
|
| `--secondary-language <n>` | string | - | Sekundäre Label-Sprache für JSDoc |
|
|
20
20
|
| `--no-forms` | flag | - | Formular-Interface-Generierung überspringen |
|
|
@@ -55,4 +55,4 @@ Erstellt ein neues D365-Formularskript-Projekt.
|
|
|
55
55
|
| `--skip-install` | flag | false | npm install überspringen |
|
|
56
56
|
| `--force` | flag | false | Nicht-leere Verzeichnisse erlauben |
|
|
57
57
|
|
|
58
|
-
Generiert 11 Dateien: package.json, tsconfig.json, xrmforge.config.json, vitest.config.ts, .gitignore, AGENT.md, example-form.ts, example-form.test.ts,
|
|
58
|
+
Generiert 11 Dateien: package.json, tsconfig.json, xrmforge.config.json, vitest.config.ts, .gitignore, AGENT.md, example-form.ts, example-form.test.ts, generated/.gitkeep, GitHub Actions CI, Azure DevOps Pipeline.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { createFormMock } from '@xrmforge/testing';
|
|
7
|
-
import type { AccountMainForm, AccountMainFormMockValues } from '../
|
|
7
|
+
import type { AccountMainForm, AccountMainFormMockValues } from '../generated/forms/account';
|
|
8
8
|
|
|
9
9
|
const mock = createFormMock<AccountMainForm, AccountMainFormMockValues>({
|
|
10
10
|
name: 'Contoso Ltd',
|
|
@@ -36,7 +36,7 @@ Verbietet rohe Zahlen (>= 2) in Vergleichen mit `.getValue()`.
|
|
|
36
36
|
if (attr.getValue() === 595300000) { }
|
|
37
37
|
|
|
38
38
|
// Richtig
|
|
39
|
-
import { StatusCode } from '../
|
|
39
|
+
import { StatusCode } from '../generated/optionsets/account';
|
|
40
40
|
if (attr.getValue() === StatusCode.Active) { }
|
|
41
41
|
```
|
|
42
42
|
|
|
@@ -35,4 +35,4 @@ Fünf KI-Modelle wurden beim Konvertieren von Legacy-D365-JavaScript (account.js
|
|
|
35
35
|
|
|
36
36
|
**Kriterien (11, maximal 5 Punkte je = 55 max):** Fields-Enum-Nutzung, OptionSet-Enums, FormContext-Typisierung, XrmForge-Helpers, Modul-Exports, Tests vorhanden, Testqualität, Fehlerbehandlung, Codequalität, gefundene Bugs, Dokumentation.
|
|
37
37
|
|
|
38
|
-
**Zentrale Erkenntnis:** Keine KI hat konsistent `@xrmforge/
|
|
38
|
+
**Zentrale Erkenntnis:** Keine KI hat konsistent `@xrmforge/helpers`-Imports (select, parseLookup) verwendet. Dies bleibt die grösste Adoptionslücke.
|
|
@@ -10,5 +10,5 @@ Bekannte Probleme bei der Arbeit mit `@types/xrm`:
|
|
|
10
10
|
| setNotification | `setNotification(message)` | `setNotification(message, uniqueId)` (erfordert 2 Argumente) |
|
|
11
11
|
| openFile | `openFile({ fileName, ... })` | Muss `fileSize`-Eigenschaft in FileDetails enthalten |
|
|
12
12
|
| SubmitMode | `Xrm.Attributes.SubmitMode` | `Xrm.SubmitMode` |
|
|
13
|
-
| const enum in .d.ts | `const enum` in `.d.ts`-Dateien |
|
|
13
|
+
| const enum in .d.ts | `const enum` in `.d.ts`-Dateien | `const enum` in `.ts`-ES-Modulen verwenden (typegen 0.8.0+ generiert `.ts`-Dateien, wodurch dieses Problem gelöst ist) |
|
|
14
14
|
| Grid.refresh() | `grid.refresh()` | `(grid as any).refresh()` (nicht typisiert in @types/xrm) |
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
## 16.2 Akzeptierte Einschränkungen
|
|
14
14
|
|
|
15
|
-
- **const-enum-Einschränkung:**
|
|
15
|
+
- **const-enum-Einschränkung:** Gelöst in typegen 0.8.0. Generierter Output sind jetzt `.ts`-ES-Module, sodass `const enum` direkt mit vitest und anderen Test-Frameworks funktioniert.
|
|
16
16
|
- **Grid.refresh() erfordert `as any`:** Nicht typisiert in @types/xrm.
|
|
17
17
|
- **Eine Solution pro Entität:** Wenn eine Entität in mehreren Solutions vorkommt, wird sie nur einmal generiert.
|