@xrmforge/devkit 0.7.1 → 0.7.2

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.
@@ -1,6 +1,22 @@
1
1
  # XrmForge - AI Agent Instructions
2
2
 
3
- This file helps AI coding assistants write optimal Dynamics 365 form scripts.
3
+ ## Quality Philosophy
4
+
5
+ The goal is not "code that compiles" or "code that passes a linter". The goal is
6
+ code that reads like a description of the business logic. A developer opening a
7
+ file should immediately understand what happens, without Xrm API docs, without
8
+ OData knowledge, without deciphering GUIDs or magic numbers.
9
+
10
+ Every string that references a Dataverse resource (field name, entity name,
11
+ OptionSet value, tab name, section name, notification ID, navigation property)
12
+ MUST come from a generated constant or a named constant from constants.ts.
13
+ No exceptions. No workarounds. No helper wrappers that accept raw strings.
14
+
15
+ Abstraction layers that merely wrap single API calls with string parameters
16
+ (getValue, setValue, setDisabled, addOnChange) destroy type safety and must not
17
+ exist. The correct abstraction is `typedForm()` (language-level proxy), not
18
+ string wrappers (API-level indirection). Business logic belongs in named
19
+ functions with domain-specific names, not in anonymous chains of API calls.
4
20
 
5
21
  ## Packages
6
22
 
@@ -533,6 +549,25 @@ Never recreate them. Use the typed API directly.
533
549
  | `SetNotification(attr, msg)` | `form.$context.getControl(Fields.X).setNotification(msg, NOTIFICATION_IDS.x)` |
534
550
  | `SetSectionDisabled(tab, sec, off)` | `form.$context.ui.tabs.get(Tabs.X).sections.get(Sections.Y).setVisible(!off)` |
535
551
 
552
+ ### GUID Handling (common CRM anti-pattern)
553
+
554
+ D365 returns GUIDs in various formats: `{A1B2C3D4-...}`, `a1b2c3d4-...`, `A1B2C3D4-...`.
555
+ Legacy code commonly has helpers like `CompareGuid()`, `GetCompatibleGuid()`,
556
+ `NormalizeGuid()`, `StripBraces()`. **Do NOT recreate these.**
557
+
558
+ `formLookupId()` from @xrmforge/helpers already normalizes GUIDs (removes braces).
559
+ GUID comparison is then a simple `===`:
560
+
561
+ ```typescript
562
+ // WRONG: legacy GUID helpers
563
+ function CompareGuid(a, b) { return a.replace(/[{}]/g,'').toLowerCase() === b.replace(/[{}]/g,'').toLowerCase(); }
564
+ const id = GetCompatibleGuid(form.getAttribute("customerid").getValue()[0].id);
565
+
566
+ // CORRECT: formLookupId normalizes automatically
567
+ const customerId = formLookupId(form.customerid); // already clean: "a1b2c3d4-..."
568
+ if (customerId === otherNormalizedId) { ... } // simple ===
569
+ ```
570
+
536
571
  **Rule of thumb:** If a helper function just wraps a single Xrm API call with a
537
572
  string parameter, it MUST NOT exist. The typed API is shorter, safer, and provides
538
573
  IDE autocomplete. Only keep shared helpers that contain actual domain logic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xrmforge/devkit",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Build orchestration and project tooling for Dynamics 365 WebResources",
5
5
  "keywords": [
6
6
  "dynamics-365",