Skip to content

Commit 2a85468

Browse files
committed
Consolidate docs into README and bump changelog to 1.1.0
1 parent fd9254c commit 2a85468

6 files changed

Lines changed: 232 additions & 248 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

33
## [Unreleased]
4+
5+
## [1.1.0] - 2026-04-13
46
### Changed
57
- Lookup JSDoc "Table:" lines now truncate to 5 target entities, appending `+N more` when there are additional targets
68
- Refactored `Comment` type to use `XrmAttributeType` DU (24 SDK attribute types) instead of strings for type-safe formatting
@@ -19,4 +21,5 @@
1921
### Added
2022
- Initial public release
2123

24+
[1.1.0]: https://github.com/Mosh-K/XrmTypeScript/releases/tag/v1.1.0
2225
[1.0.0]: https://github.com/Mosh-K/XrmTypeScript/releases/tag/v1.0.0

README.md

Lines changed: 229 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,236 @@ If you haven't worked with TypeScript tooling before, you'll need a `tsconfig.js
5353
```
5454

5555

56-
## Documentation
56+
## Form Scripting
57+
58+
XrmTypeScript generates form-specific TypeScript interfaces for your Dynamics 365 forms,
59+
giving you full intellisense and type safety.
60+
61+
### Specific Account Form Example
62+
63+
In this example, we want to add code to the standard Account form called
64+
'Information', which is of the 'Main' form type. This can be found at
65+
`Form/account/Main/Information.d.ts`. Simply by adding this to your TypeScript context,
66+
you get access to the specific Xrm object model API for that form.
67+
68+
#### JavaScript
69+
70+
Use JSDoc comments to get intellisense and type support:
71+
72+
```javascript
73+
/**
74+
* @param {Xrm.Events.LoadEventContext} executionContext
75+
*/
76+
function onLoad(executionContext) {
77+
/** @type {Form.account.Main.Information} */
78+
let form = executionContext.getFormContext();
79+
// Code here..
80+
form.getAttribute("accountnumber").addOnChange(checkAccount);
81+
}
82+
83+
/**
84+
* @param {Xrm.ChangeEventContext<Form.account.Main.Information>} executionContext
85+
*/
86+
function checkAccount(executionContext) {
87+
let form = executionContext.getFormContext();
88+
// Code here..
89+
let accountNumber = form.getAttribute("accountnumber").getValue();
90+
}
91+
```
92+
93+
#### TypeScript
94+
95+
```typescript
96+
function onLoad(executionContext: Xrm.LoadEventContext) {
97+
let form: Form.account.Main.Information = executionContext.getFormContext();
98+
// Code here..
99+
form.getAttribute("accountnumber").addOnChange(checkAccount);
100+
}
101+
102+
function checkAccount(executionContext: Xrm.ChangeEventContext<Form.account.Main.Information>) {
103+
let form = executionContext.getFormContext();
104+
// Code here..
105+
let accountNumber = form.getAttribute("accountnumber").getValue();
106+
}
107+
```
108+
109+
> Remember to tick **Pass execution context as first parameter** in CRM when adding your function to the form.
110+
111+
### Type Safety
112+
113+
In your desired IDE, you will now get intellisense for that specific
114+
account form, with all of its attributes, controls, tabs and sections.
115+
116+
Each attribute and control on the form has the correct type, giving you type safety on values and functions.
117+
If an invalid string is entered as an argument to one of the string-specific functions, the compiler will
118+
show an error — making it easy to catch incorrect attribute names or attempts to access elements that are
119+
not present on the form.
120+
121+
122+
## Web API & Entities
123+
124+
XrmTypeScript generates TypeScript interfaces that precisely reflect the structure of data returned
125+
by the Dataverse OData endpoint. Every entity in your solution gets its own set of interfaces —
126+
one for retrieval, one for create, and one for update — each typed to the exact shape the API
127+
expects or returns.
128+
129+
This means you get full compile-time safety across your entire data layer: the correct property
130+
names and types on retrieved records, typed nested objects for deep insert, the `@odata.bind`
131+
syntax for associating existing records, formatted values and lookup metadata available as typed
132+
properties, and relationship traversal with full intellisense on related records. Mistakes that
133+
would previously only surface at runtime are caught by the compiler before they reach your CRM instance.
134+
135+
The generated interfaces work anywhere you query the Dataverse API — on forms via `Xrm.WebApi`,
136+
in PCF components, or in external TypeScript projects using `fetch` or any HTTP client.
137+
138+
### Retrieve
139+
140+
```typescript
141+
// Using Xrm.WebApi
142+
const contact: WebApi.Contact = await Xrm.WebApi.retrieveRecord("contact", id, options);
143+
144+
// Using fetch
145+
const response = await fetch(`/api/data/v9.2/contacts(${id})${options}`);
146+
const contact: WebApi.Contact = await response.json();
147+
148+
// TypeScript knows birthdate is Date | null | undefined
149+
const birthdate = contact.birthdate;
150+
// Formatted values are typed as string | undefined
151+
const formattedBirthdate = contact["birthdate@OData.Community.Display.V1.FormattedValue"];
152+
153+
// Lookup — intellisense shows all SystemUser properties
154+
const createdBy = contact.createdby;
155+
const createdByName = createdBy?.nickname;
156+
157+
// Related collection — each account is fully typed as WebApi.Account
158+
const accounts = contact.account_primary_contact;
159+
accounts?.forEach((account) => {
160+
const name = account.name; // string | null | undefined
161+
const shippingMethodFormatted = account["address2_shippingmethodcode@OData.Community.Display.V1.FormattedValue"];
162+
});
163+
```
164+
165+
### Create
166+
167+
```typescript
168+
const newContact: WebApi.Contact.Create = {
169+
firstname: "John",
170+
lastname: "Doe",
171+
emailaddress1: "john.doe@example.com",
172+
birthdate: new Date("1990-01-01"),
173+
// Deep insert — compiler enforces the shape of the nested Account
174+
parentcustomerid_account: {
175+
creditlimit: 10000,
176+
name: "Contoso",
177+
}
178+
};
179+
180+
// Using Xrm.WebApi
181+
await Xrm.WebApi.createRecord("contact", newContact);
182+
183+
// Using fetch
184+
await fetch("/api/data/v9.2/contacts", {
185+
method: "POST",
186+
headers: { "Content-Type": "application/json" },
187+
body: JSON.stringify(newContact),
188+
});
189+
```
190+
191+
### Update
192+
193+
```typescript
194+
const updatedContact: WebApi.Contact.Update = {
195+
firstname: "Jane",
196+
lastname: "Smith",
197+
emailaddress1: "jane.smith@example.com",
198+
// @odata.bind — typed as a template literal to enforce the correct URL format
199+
"parentcustomerid_account@odata.bind": "/accounts(00000000-0000-0000-0000-000000001234)",
200+
};
201+
202+
// Using Xrm.WebApi
203+
await Xrm.WebApi.updateRecord("contact", "00000000-0000-0000-0000-000000000001", updatedContact);
204+
205+
// Using fetch
206+
await fetch("/api/data/v9.2/contacts(00000000-0000-0000-0000-000000000001)", {
207+
method: "PATCH",
208+
headers: { "Content-Type": "application/json" },
209+
body: JSON.stringify(updatedContact),
210+
});
211+
```
212+
213+
214+
## Tool Arguments
215+
216+
Arguments can be passed via the `XrmTypeScript.exe.config` file or directly from the command line.
217+
218+
### Arguments
219+
220+
#### Connection
221+
222+
| Argument | Short-hand | Description |
223+
| :--------------- | :--------- | :------------------------------------------- |
224+
| url | | URL to the organization |
225+
| method | m | OAuth, ClientSecret or ConnectionString |
226+
| appId | id | Azure Application Id |
227+
| clientSecret | cs | Client secret for the Azure Application |
228+
| returnUrl | | Return URL of the Azure Application |
229+
| connectionString | | Connection String used for authentication |
230+
| username | u, usr | Username for the CRM system |
231+
| password | p, pwd | Password for the CRM system |
232+
| domain | d, dmn | Domain for the user |
233+
| ap | | Authentication Provider Type |
234+
235+
#### Generation
236+
237+
| Argument | Short-hand | Description |
238+
| :---------------- | :--------- | :--------------------------------------------------------------------------------------------------------------- |
239+
| out | o | Output directory for the generated declaration files |
240+
| solutions | ss | Comma-separated list of solution names. Generates code for the entities found in these solutions. |
241+
| entities | es | Comma-separated list of entity logical names. Additive with the entities retrieved via the `solutions` argument. |
242+
| web | w | Set to true to generate declaration files for Web entities |
243+
| skipXrmApi | sxa | Set to true to skip generation of Xrm.WebApi overloads |
244+
| crmVersion | cv | Version of CRM to generate declaration files for |
245+
| oneFile | of | Set to true to put all dynamic parts of the generated declarations into a single file |
246+
| skipForms | sf | Set to true to skip generation of form declaration files |
247+
| skipInactiveForms | sif | Set to true to avoid generating types for inactive forms |
248+
| useDeprecated | ud | Set to true to include typings for deprecated functionality |
249+
| useconfig | uc | Also applies the arguments found in the `.config` file |
250+
251+
You can also view this list of arguments using the `/help` argument.
252+
253+
### Command Line
254+
255+
```bash
256+
XrmTypeScript.exe /url:https://INSTANCE.crm4.dynamics.com /method:ClientSecret /id:<APP_ID> /cs:<CLIENT_SECRET>
257+
```
258+
259+
If you want to use a mix of the arguments from the configuration file and arguments passed to the executable,
260+
you can use the `/useconfig` argument from the command-line.
261+
262+
```bash
263+
XrmTypeScript.exe /useconfig /entities:account,contact
264+
```
265+
266+
267+
## XrmTypeScript vs XrmDefinitelyTyped
268+
269+
XrmTypeScript is a fork of [XrmDefinitelyTyped](https://github.com/delegateas/XrmDefinitelyTyped) by Delegateas.
270+
The following is a list of the key differences.
271+
272+
### What's Different
273+
274+
- **Modern type foundation** — Xrm types are based on the modern [`@types/xrm`](https://www.npmjs.com/package/@types/xrm) library.
275+
- **Non-English support** — Support for non-English environments.
276+
- **Improved generation performance** — Type generation is significantly faster for solutions with large numbers of entities.
277+
- **No bundled JavaScript library** — XrmQuery and its runtime dependencies have been removed. XrmTypeScript generates types only, with no runtime overhead.
278+
- **OData-aligned entity interfaces** — The generated entity interfaces reflect the actual structure of data returned by the Dataverse OData endpoint, making them directly usable with `Xrm.WebApi` or any HTTP client.
279+
- **Xrm.WebApi overloads** — XrmTypeScript generates typed overloads for the native `Xrm.WebApi` methods.
280+
- **Richer generated output** — Types include comments with display names, column types, and enum links, making the generated code more informative in your IDE.
281+
- **`getAttribute` and `getControl` work with arrays of field names** — Iterating over a list of known field names correctly resolves each return type, instead of falling through to `undefined`.
282+
- **Attribute and control mappings are always generated** — The `generateMappings` argument has been removed. Mappings are now included in the generated output by default.
283+
- **`-web` argument** — Accepts a boolean instead of a namespace string. The generated entity interfaces are placed in the `WebApi` namespace by default.
284+
- **View generation removed** — The `-views` argument and generation have been removed.
57285

58-
- [Tool Arguments](docs/tool-arguments.md)
59-
- [Form Scripting](docs/form-scripting.md)
60-
- [Web API & Entities](docs/web-api.md)
61-
- [Comparison with XrmDefinitelyTyped](docs/comparison.md)
62286

63287
## Acknowledgements
64288

docs/comparison.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

docs/form-scripting.md

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)