Microsoft Power Platform/Dynamics 365 CE - Generate TypeScript Definitions

Automatically creates TypeScript type definitions compatible with @types/xrm by extracting form attributes and controls from Dynamics 365/Power Platform model-driven applications.

  1. // ==UserScript==
  2. // @name Microsoft Power Platform/Dynamics 365 CE - Generate TypeScript Definitions
  3. // @namespace https://github.com/gncnpk/xrm-generate-ts-overloads
  4. // @author Gavin Canon-Phratsachack (https://github.com/gncnpk)
  5. // @version 1.998
  6. // @license MIT
  7. // @description Automatically creates TypeScript type definitions compatible with @types/xrm by extracting form attributes and controls from Dynamics 365/Power Platform model-driven applications.
  8. // @match https://*.dynamics.com/main.aspx?appid=*&pagetype=entityrecord&etn=*&id=*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. "use strict";
  14.  
  15. const groupItemsByType = (items) => {
  16. return Object.entries(items).reduce((acc, [itemName, itemType]) => {
  17. if (!acc[itemType]) {
  18. acc[itemType] = [];
  19. }
  20. acc[itemType].push(itemName);
  21. return acc;
  22. }, {});
  23. };
  24. const stripNonAlphaNumeric = (str) => {
  25. return str.replace(/\W/g, "");
  26. };
  27. // Create a button element and style it to be fixed in the bottom-right corner.
  28. const btn = document.createElement("button");
  29. btn.textContent = "Generate TypeScript Definitions";
  30. btn.style.position = "fixed";
  31. btn.style.bottom = "20px";
  32. btn.style.right = "20px";
  33. btn.style.padding = "10px";
  34. btn.style.backgroundColor = "#007ACC";
  35. btn.style.color = "#fff";
  36. btn.style.border = "none";
  37. btn.style.borderRadius = "5px";
  38. btn.style.cursor = "pointer";
  39. btn.style.zIndex = 10000;
  40. document.body.appendChild(btn);
  41.  
  42. btn.addEventListener("click", () => {
  43. // Mapping objects for Xrm attribute and control types.
  44. var attributeTypeMapping = {
  45. boolean: "Xrm.Attributes.BooleanAttribute",
  46. datetime: "Xrm.Attributes.DateAttribute",
  47. decimal: "Xrm.Attributes.NumberAttribute",
  48. double: "Xrm.Attributes.NumberAttribute",
  49. integer: "Xrm.Attributes.NumberAttribute",
  50. lookup: "Xrm.Attributes.LookupAttribute",
  51. memo: "Xrm.Attributes.StringAttribute",
  52. money: "Xrm.Attributes.NumberAttribute",
  53. multiselectoptionset: "Xrm.Attributes.MultiselectOptionSetAttribute",
  54. optionset: "Xrm.Attributes.OptionSetAttribute",
  55. string: "Xrm.Attributes.StringAttribute",
  56. };
  57.  
  58. var controlTypeMapping = {
  59. standard: "Xrm.Controls.StandardControl",
  60. iframe: "Xrm.Controls.IframeControl",
  61. lookup: "Xrm.Controls.LookupControl",
  62. optionset: "Xrm.Controls.OptionSetControl",
  63. "customsubgrid:MscrmControls.Grid.GridControl":
  64. "Xrm.Controls.GridControl",
  65. subgrid: "Xrm.Controls.GridControl",
  66. timelinewall: "Xrm.Controls.TimelineWall",
  67. quickform: "Xrm.Controls.QuickFormControl",
  68. formcomponent: "Xrm.FormContext",
  69. };
  70.  
  71. var specificControlTypeMapping = {
  72. boolean: "Xrm.Controls.BooleanControl",
  73. datetime: "Xrm.Controls.DateControl",
  74. decimal: "Xrm.Controls.NumberControl",
  75. double: "Xrm.Controls.NumberControl",
  76. integer: "Xrm.Controls.NumberControl",
  77. lookup: "Xrm.Controls.LookupControl",
  78. memo: "Xrm.Controls.StringControl",
  79. money: "Xrm.Controls.NumberControl",
  80. multiselectoptionset: "Xrm.Controls.MultiselectOptionSetControl",
  81. optionset: "Xrm.Controls.OptionSetControl",
  82. string: "Xrm.Controls.StringControl",
  83. };
  84.  
  85. // Object to hold the type information.
  86. const typeInfo = {
  87. subGrids: {},
  88. quickViews: {},
  89. formAttributes: {},
  90. formControls: {},
  91. subForms: {},
  92. possibleEnums: [],
  93. formTabs: {},
  94. formEnums: {},
  95. };
  96.  
  97. class Form {
  98. constructor() {
  99. this.attributes = {};
  100. this.controls = {};
  101. this.enums = {};
  102. this.subGrids = {};
  103. this.quickViews = {};
  104. }
  105. }
  106. class Subgrid {
  107. constructor() {
  108. this.attributes = {};
  109. this.enums = {};
  110. }
  111. }
  112. class QuickForm {
  113. constructor() {
  114. this.attributes = {};
  115. this.controls = {};
  116. this.enums = {};
  117. }
  118. }
  119.  
  120. class Tab {
  121. constructor() {
  122. this.sections = {};
  123. }
  124. }
  125.  
  126. const currentFormName = stripNonAlphaNumeric(
  127. Xrm.Page.ui.formSelector.getCurrentItem().getLabel()
  128. );
  129.  
  130. // Loop through all controls on the form.
  131. function getControls(formContext, controlObject) {
  132. if (
  133. typeof formContext !== "undefined" &&
  134. formContext &&
  135. typeof formContext.getControl === "function"
  136. ) {
  137. formContext.getControl().forEach((ctrl) => {
  138. const ctrlType = ctrl.getControlType();
  139. const mappedType = controlTypeMapping[ctrlType];
  140. if (mappedType) {
  141. controlObject[ctrl.getName()] = mappedType;
  142. }
  143. });
  144. } else {
  145. alert("Xrm.Page is not available on this page.");
  146. return;
  147. }
  148. }
  149.  
  150. getControls(Xrm.Page, typeInfo.formControls);
  151.  
  152. // Loop through all tabs and sections on the form.
  153. if (typeof Xrm.Page.ui.tabs.get === "function") {
  154. Xrm.Page.ui.tabs.get().forEach((tab) => {
  155. let formTab = (typeInfo.formTabs[stripNonAlphaNumeric(tab.getName())] =
  156. new Tab());
  157. tab.sections.forEach((section) => {
  158. formTab.sections[
  159. stripNonAlphaNumeric(section.getName())
  160. ] = `${stripNonAlphaNumeric(section.getName())}_section`;
  161. });
  162. });
  163. }
  164.  
  165. // Loop through all attributes on the form.
  166. function getAttributes(
  167. formContext,
  168. attributesObject,
  169. controlsObject,
  170. enumsObject
  171. ) {
  172. if (typeof formContext.getAttribute === "function") {
  173. formContext.getAttribute().forEach((attr) => {
  174. const attrType = attr.getAttributeType();
  175. const attrName = attr.getName();
  176. const mappedType = attributeTypeMapping[attrType];
  177. const mappedControlType = specificControlTypeMapping[attrType];
  178. if (mappedType) {
  179. attributesObject[attrName] = mappedType;
  180. attr.controls.forEach((ctrl) => {
  181. controlsObject[ctrl.getName()] = mappedControlType;
  182. });
  183. }
  184. if (
  185. attr.getAttributeType() === "optionset" &&
  186. attr.controls.get().length > 0
  187. ) {
  188. const enumValues = attr.getOptions();
  189. if (enumValues) {
  190. enumsObject[attrName] = { attribute: "", values: [] };
  191. enumsObject[attrName].values = enumValues;
  192. enumsObject[attrName].attribute = attrName;
  193. attributesObject[attrName] = `${attrName}_attribute`;
  194. }
  195. }
  196. });
  197. }
  198. }
  199. getAttributes(
  200. Xrm.Page,
  201. typeInfo.formAttributes,
  202. typeInfo.formControls,
  203. typeInfo.formEnums
  204. );
  205.  
  206. // Loop through all subgrids on the form.
  207. function getSubGrids(formContext, subGridsObject, controlsObject) {
  208. if (typeof formContext.getControl === "function") {
  209. formContext.getControl().forEach((ctrl) => {
  210. if (
  211. ctrl.getControlType() === "subgrid" ||
  212. ctrl.getControlType() ===
  213. "customsubgrid:MscrmControls.Grid.GridControl"
  214. ) {
  215. const gridRow = ctrl.getGrid().getRows().get(0);
  216. const gridName = ctrl.getName();
  217. let subgrid = (subGridsObject[gridName] = new Subgrid());
  218. controlsObject[gridName] = `${gridName}_gridcontrol`;
  219. if (gridRow !== null) {
  220. gridRow.data.entity.attributes.forEach((attr) => {
  221. const attrType = attr.getAttributeType();
  222. const attrName = attr.getName();
  223. const mappedType = attributeTypeMapping[attrType];
  224. if (mappedType) {
  225. subgrid.attributes[attrName] = mappedType;
  226. }
  227. if (
  228. attr.getAttributeType() === "optionset" &&
  229. attr.controls.get().length > 0
  230. ) {
  231. const enumValues = attr.getOptions();
  232. if (enumValues) {
  233. subgrid.enums[attrName] = { attribute: "", values: [] };
  234. subgrid.enums[attrName].values = enumValues;
  235. subgrid.enums[attrName].attribute = attrName;
  236. subgrid.attributes[attrName] = `${attrName}_attribute`;
  237. }
  238. }
  239. });
  240. }
  241. }
  242. });
  243. }
  244. }
  245. getSubGrids(Xrm.Page, typeInfo.subGrids, typeInfo.formControls);
  246.  
  247. if (typeof Xrm.Page.getControl === "function") {
  248. Xrm.Page.getControl().forEach((ctrl) => {
  249. if (ctrl.getControlType() === "formcomponent") {
  250. let formObject = (typeInfo.subForms[`${ctrl.getName()}`] =
  251. new Form());
  252. try {
  253. getControls(ctrl, formObject.controls);
  254. getAttributes(
  255. ctrl,
  256. formObject.attributes,
  257. formObject.controls,
  258. formObject.enums
  259. );
  260. getSubGrids(ctrl, formObject.subGrids, formObject.controls);
  261. getQuickViews(ctrl, formObject.quickViews, formObject.controls);
  262. } catch {}
  263. }
  264. });
  265. }
  266. function generateEnums(possibleEnums, enumsObject) {
  267. for (const [originalEnumName, enumValues] of Object.entries(
  268. enumsObject
  269. )) {
  270. if (possibleEnums.includes(originalEnumName)) {
  271. continue;
  272. }
  273. possibleEnums.push(originalEnumName);
  274. let enumName = `${originalEnumName}_enum`;
  275. let enumTemplate = [];
  276. let textLiteralTypes = [];
  277. let valueLiteralTypes = [];
  278. for (const enumValue of enumValues.values) {
  279. enumTemplate.push(
  280. ` ${enumValue.text.replace(/\W/g, "").replace(/[0-9]/g, "")} = ${
  281. enumValue.value
  282. }`
  283. );
  284. textLiteralTypes.push(`"${enumValue.text}"`);
  285. valueLiteralTypes.push(
  286. `${enumName}.${enumValue.text
  287. .replace(/\W/g, "")
  288. .replace(/[0-9]/g, "")}`
  289. );
  290. }
  291. outputTS += `
  292. const enum ${enumName} {
  293. ${enumTemplate.join(",\n")}
  294. }
  295. `;
  296. outputTS += `
  297. interface ${enumValues.attribute}_value extends Xrm.OptionSetValue {
  298. text: ${textLiteralTypes.join(" | ")};
  299. value: ${valueLiteralTypes.join(" | ")};
  300. }
  301. `;
  302. outputTS += `
  303. interface ${enumValues.attribute}_attribute extends Xrm.Attributes.OptionSetAttribute<${enumName}> {
  304. `;
  305. valueLiteralTypes.forEach((value, index) => {
  306. outputTS += `getOption(value: ${value}): {text: ${textLiteralTypes[index]}, value: ${value}};\n`;
  307. });
  308. outputTS += `getOption(value: ${enumValues.attribute}_value['value']): ${enumValues.attribute}_value | null;
  309. getOptions(): ${enumValues.attribute}_value[];
  310. getSelectedOption(): ${enumValues.attribute}_value | null;
  311. getValue(): ${enumName} | null;
  312. setValue(value: ${enumName} | null): void;
  313. getText(): ${enumValues.attribute}_value['text'] | null;
  314. }
  315. `;
  316. }
  317. }
  318.  
  319. function generateLiteralsTypesUnionsAndCollection(
  320. unionAndCollectionName,
  321. literalsAndTypesObject,
  322. defaultType = "unknown",
  323. generateCollection = true,
  324. useLiteralAndAppendToType = ""
  325. ) {
  326. if (generateCollection) {
  327. outputTS += `
  328. interface ${unionAndCollectionName} extends Xrm.Collection.ItemCollection<${unionAndCollectionName}_types> {`;
  329. if (useLiteralAndAppendToType) {
  330. for (const [literal, type] of Object.entries(
  331. literalsAndTypesObject
  332. )) {
  333. outputTS += `get(itemName: "${literal}"): ${literal}${useLiteralAndAppendToType};\n`;
  334. }
  335. } else {
  336. for (const [type, literal] of Object.entries(
  337. groupItemsByType(literalsAndTypesObject)
  338. )) {
  339. outputTS += `get(itemName: "${literal.join('" | "')}"): ${type};\n`;
  340. }
  341. }
  342. outputTS += `
  343. get(itemName: ${unionAndCollectionName}_literals): ${unionAndCollectionName}_types;
  344. get(itemNameOrIndex: string | number): ${unionAndCollectionName} | null;
  345. get(delegate?): ${unionAndCollectionName}_types[];
  346. }
  347. `;
  348. }
  349. if (useLiteralAndAppendToType) {
  350. outputTS += `
  351. type ${unionAndCollectionName}_types = ${new Set(
  352. Object.keys(literalsAndTypesObject)
  353. )
  354. .map((literal) => `${literal}${useLiteralAndAppendToType}`)
  355. .join(" | ")}${
  356. Object.keys(literalsAndTypesObject).length === 0 ? defaultType : ""
  357. };\n`;
  358. } else {
  359. outputTS += `
  360. type ${unionAndCollectionName}_types = ${new Set(
  361. Object.values(literalsAndTypesObject)
  362. )
  363. .map((type) => `${type}`)
  364. .join(" | ")}${
  365. Object.keys(literalsAndTypesObject).length === 0 ? defaultType : ""
  366. };\n`;
  367. }
  368.  
  369. outputTS += `
  370. type ${unionAndCollectionName}_literals = ${new Set(
  371. Object.keys(literalsAndTypesObject)
  372. )
  373. .map((literal) => `"${literal}"`)
  374. .join(" | ")}${
  375. Object.keys(literalsAndTypesObject).length === 0 ? '""' : ""
  376. };\n`;
  377. }
  378.  
  379. function generateSubgridTypes(subgridName) {
  380. outputTS += `
  381. interface ${subgridName}_entity extends Xrm.Entity {
  382. attributes: ${subgridName}_attributes;
  383. }
  384. interface ${subgridName}_data extends Xrm.Data {
  385. entity: ${subgridName}_entity;
  386. }
  387. interface ${subgridName}_gridrow extends Xrm.Controls.Grid.GridRow {
  388. data: ${subgridName}_data;
  389. }
  390. interface ${subgridName}_grid extends Xrm.Controls.Grid {
  391. getRows(): Xrm.Collection.ItemCollection<${subgridName}_gridrow>;
  392. }
  393. interface ${subgridName}_gridcontrol extends Xrm.Controls.GridControl {
  394. getGrid(): ${subgridName}_grid;
  395. }`;
  396. }
  397. function generateContext(
  398. formName,
  399. contextType,
  400. attributesObject,
  401. controlsObject,
  402. uiType = null
  403. ) {
  404. let contextSuffix;
  405. if (contextType === "Xrm.FormContext") {
  406. contextSuffix = `context`;
  407. } else if (contextType === "Xrm.Controls.QuickFormControl") {
  408. contextSuffix = `quickformcontrol`;
  409. }
  410. outputTS += `
  411. interface ${formName}_${contextSuffix} extends ${contextType} {`;
  412. if (uiType) {
  413. outputTS += `ui: ${uiType};`;
  414. }
  415. if (attributesObject) {
  416. for (const [attrType, attrNames] of Object.entries(
  417. groupItemsByType(attributesObject)
  418. )) {
  419. outputTS += `getAttribute(attributeName: "${attrNames.join(
  420. '" | "'
  421. )}"): ${attrType};\n`;
  422. }
  423. outputTS += `getAttribute(attributeName: ${formName}_attributes_literals): ${formName}_attributes_types;`;
  424. outputTS += `getAttribute(attributeNameOrIndex: string | number): Xrm.Attributes.Attribute | null;`;
  425. outputTS += `getAttribute(delegateFunction?): ${formName}_attributes[];`;
  426. }
  427. if (controlsObject) {
  428. for (const [controlType, controlNames] of Object.entries(
  429. groupItemsByType(controlsObject)
  430. )) {
  431. outputTS += `getControl(controlName: "${controlNames.join(
  432. '" | "'
  433. )}"): ${controlType};\n`;
  434. }
  435. outputTS += `getControl(controlName: ${formName}_controls_literals): ${formName}_controls_types;`;
  436. outputTS += `getControl(controlNameOrIndex: string | number): Xrm.Controls.Control | null;`;
  437. outputTS += `getControl(delegateFunction?): ${formName}_controls_types[];`;
  438. }
  439. outputTS += `}`;
  440. outputTS += `
  441. interface ${formName}_eventcontext extends Xrm.Events.EventContext {
  442. getFormContext(): ${formName}_${contextSuffix};
  443. }`;
  444. }
  445. // Loop through all Quick View controls and attributes on the form.
  446. function getQuickViews(formContext, quickViewsObject, controlsObject) {
  447. if (typeof formContext.ui.quickForms.get === "function") {
  448. formContext.ui.quickForms.get().forEach((ctrl) => {
  449. const quickViewName = ctrl.getName();
  450. let quickView = (quickViewsObject[quickViewName] = new QuickForm());
  451. controlsObject[quickViewName] = `${quickViewName}_quickformcontrol`;
  452. ctrl.getControl().forEach((subCtrl) => {
  453. if (typeof subCtrl.getAttribute !== "function") {
  454. return;
  455. }
  456. const subCtrlAttrType = subCtrl.getAttribute().getAttributeType();
  457. const mappedControlType =
  458. specificControlTypeMapping[subCtrlAttrType] ??
  459. controlTypeMapping[subCtrl.getControlType()];
  460. if (mappedControlType) {
  461. quickView.controls[subCtrl.getName()] = mappedControlType;
  462. }
  463. });
  464. ctrl.getAttribute().forEach((attr) => {
  465. const attrType = attr.getAttributeType();
  466. const attrName = attr.getName();
  467. const mappedType = attributeTypeMapping[attrType];
  468. if (mappedType) {
  469. quickView.attributes[attrName] = mappedType;
  470. }
  471. if (attrType === "optionset" && attr.controls.get().length > 0) {
  472. const enumValues = attr.getOptions();
  473. if (enumValues) {
  474. quickView.enums[attrName] = { attribute: "", values: [] };
  475. quickView.enums[attrName].values = enumValues;
  476. quickView.enums[attrName].attribute = attrName;
  477. quickView.attributes[attrName] = `${attrName}_attribute`;
  478. }
  479. }
  480. });
  481. });
  482. }
  483. }
  484. getQuickViews(Xrm.Page, typeInfo.quickViews, typeInfo.formControls);
  485.  
  486. // Build the TypeScript overload string.
  487. let outputTS = `// These TypeScript definitions were generated automatically on: ${new Date().toDateString()}\n`;
  488. generateEnums(typeInfo.possibleEnums, typeInfo.formEnums);
  489. for (let [subgridName, subgrid] of Object.entries(typeInfo.subGrids)) {
  490. subgridName = subgridName.replace(/\W/g, "");
  491. generateEnums(typeInfo.possibleEnums, subgrid.enums);
  492. generateLiteralsTypesUnionsAndCollection(
  493. `${subgridName}_attributes`,
  494. subgrid.attributes,
  495. "Xrm.Attributes.Attribute",
  496. true
  497. );
  498. generateSubgridTypes(subgridName);
  499. generateContext(`${subgridName}`, `Xrm.FormContext`, subgrid.attributes);
  500. }
  501. for (const [quickViewName, quickView] of Object.entries(
  502. typeInfo.quickViews
  503. )) {
  504. generateEnums(typeInfo.possibleEnums, quickView.enums);
  505. generateLiteralsTypesUnionsAndCollection(
  506. `${quickViewName}_attributes`,
  507. quickView.attributes,
  508. "Xrm.Attributes.Attribute",
  509. false
  510. );
  511. generateLiteralsTypesUnionsAndCollection(
  512. `${quickViewName}_controls`,
  513. quickView.controls,
  514. "Xrm.Controls.Control",
  515. false
  516. );
  517. generateContext(
  518. `${quickViewName}`,
  519. `Xrm.Controls.QuickFormControl`,
  520. quickView.attributes,
  521. quickView.controls
  522. );
  523. }
  524.  
  525. for (const [tabName, tab] of Object.entries(typeInfo.formTabs)) {
  526. outputTS += `
  527. type ${tabName}_sections_literals = ${new Set(Object.keys(tab.sections))
  528. .map((sectionName) => `"${sectionName}"`)
  529. .join(" | ")}${Object.keys(tab.sections).length === 0 ? '""' : ""};\n`;
  530. outputTS += `
  531. interface ${tabName}_sections extends Xrm.Collection.ItemCollection<Xrm.Controls.Section> {`;
  532. outputTS += `get(itemName: ${tabName}_sections_literals): Xrm.Controls.Section;\n`;
  533. outputTS += `get(itemNameOrIndex: string | number): Xrm.Controls.Section | null;\n`;
  534. outputTS += `get(delegate?): Xrm.Controls.Section[];\n`;
  535. outputTS += `}`;
  536.  
  537. outputTS += `
  538. interface ${tabName}_tab extends Xrm.Controls.Tab {
  539. sections: ${tabName}_sections;
  540. }`;
  541. }
  542. generateLiteralsTypesUnionsAndCollection(
  543. `${currentFormName}_tabs`,
  544. typeInfo.formTabs,
  545. "Xrm.Controls.Tab",
  546. true,
  547. "_tab"
  548. );
  549. generateLiteralsTypesUnionsAndCollection(
  550. `${currentFormName}_quickforms`,
  551. typeInfo.quickViews,
  552. "Xrm.Controls.QuickFormControl",
  553. true,
  554. "_quickformcontrol"
  555. );
  556. generateLiteralsTypesUnionsAndCollection(
  557. `${currentFormName}_controls`,
  558. typeInfo.formControls,
  559. "Xrm.Controls.Control",
  560. false
  561. );
  562. generateLiteralsTypesUnionsAndCollection(
  563. `${currentFormName}_attributes`,
  564. typeInfo.formAttributes,
  565. "Xrm.Attributes.Attribute",
  566. false
  567. );
  568. outputTS += `
  569. interface ${currentFormName}_ui extends Xrm.Ui {
  570. quickForms: ${currentFormName}_quickforms | null;
  571. tabs: ${currentFormName}_tabs;
  572. }
  573. `;
  574. generateContext(
  575. currentFormName,
  576. `Xrm.FormContext`,
  577. typeInfo.formAttributes,
  578. typeInfo.formControls,
  579. `${currentFormName}_ui`
  580. );
  581.  
  582. for (const [formName, formObject] of Object.entries(typeInfo.subForms)) {
  583. generateEnums(typeInfo.possibleEnums, formObject.enums);
  584. for (let [subgridName, subgrid] of Object.entries(formObject.subGrids)) {
  585. subgridName = subgridName.replace(/\W/g, "");
  586. generateEnums(typeInfo.possibleEnums, subgrid.enums);
  587. generateLiteralsTypesUnionsAndCollection(
  588. `${subgridName}_attributes`,
  589. subgrid.attributes,
  590. "Xrm.Attributes.Attribute",
  591. true
  592. );
  593. generateSubgridTypes(subgridName);
  594. generateContext(
  595. `${subgridName}`,
  596. `Xrm.FormContext`,
  597. subgrid.attributes
  598. );
  599. }
  600. for (const [quickViewName, quickView] of Object.entries(
  601. formObject.quickViews
  602. )) {
  603. generateEnums(typeInfo.possibleEnums, quickView.enums);
  604. generateLiteralsTypesUnionsAndCollection(
  605. `${quickViewName}_attributes`,
  606. quickView.attributes,
  607. "Xrm.Attributes.Attribute",
  608. false
  609. );
  610. generateLiteralsTypesUnionsAndCollection(
  611. `${quickViewName}_controls`,
  612. quickView.controls,
  613. "Xrm.Controls.Control",
  614. false
  615. );
  616. generateContext(
  617. `${quickViewName}`,
  618. `Xrm.Controls.QuickFormControl`,
  619. quickView.attributes,
  620. quickView.controls
  621. );
  622. }
  623. generateLiteralsTypesUnionsAndCollection(
  624. `${formName}_attributes`,
  625. formObject.attributes,
  626. "Xrm.Attributes.Attribute",
  627. false
  628. );
  629. generateLiteralsTypesUnionsAndCollection(
  630. `${formName}_controls`,
  631. formObject.controls,
  632. "Xrm.Controls.Control",
  633. false
  634. );
  635. generateContext(
  636. formName,
  637. `Xrm.FormContext`,
  638. formObject.attributes,
  639. formObject.controls
  640. );
  641. }
  642.  
  643. // Create a new window with a textarea showing the output.
  644. // The textarea is set to readonly to prevent editing.
  645. const w = window.open(
  646. "",
  647. "_blank",
  648. "width=600,height=400,menubar=no,toolbar=no,location=no,resizable=yes"
  649. );
  650. if (w) {
  651. w.document.write(
  652. "<html><head><title>TypeScript Definitions</title></head><body>"
  653. );
  654. w.document.write(
  655. '<textarea readonly style="width:100%; height:90%;">' +
  656. outputTS +
  657. "</textarea>"
  658. );
  659. w.document.write("</body></html>");
  660. w.document.close();
  661. } else {
  662. // Fallback to prompt if popups are blocked.
  663. prompt("Copy the TypeScript definition:", outputTS);
  664. }
  665. });
  666. })();