@khester/create-dynamics-app 1.1.0 → 2.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/README.md +74 -0
- package/dist/artifacts/registry.d.ts +18 -0
- package/dist/artifacts/registry.d.ts.map +1 -0
- package/dist/artifacts/registry.js +340 -0
- package/dist/artifacts/registry.js.map +1 -0
- package/dist/artifacts/types.d.ts +122 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +7 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/validators.d.ts +16 -0
- package/dist/artifacts/validators.d.ts.map +1 -0
- package/dist/artifacts/validators.js +45 -0
- package/dist/artifacts/validators.js.map +1 -0
- package/dist/fromDesign.d.ts +5 -0
- package/dist/fromDesign.d.ts.map +1 -0
- package/dist/fromDesign.js +98 -0
- package/dist/fromDesign.js.map +1 -0
- package/dist/index.js +129 -177
- package/dist/index.js.map +1 -1
- package/dist/injectDevTools.d.ts +28 -0
- package/dist/injectDevTools.d.ts.map +1 -0
- package/dist/injectDevTools.js +148 -0
- package/dist/injectDevTools.js.map +1 -0
- package/dist/scaffold.d.ts +48 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +180 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/templatePlan.d.ts +3 -0
- package/dist/templatePlan.d.ts.map +1 -0
- package/dist/templatePlan.js +43 -0
- package/dist/templatePlan.js.map +1 -0
- package/dist/utils/copyTemplate.d.ts +13 -1
- package/dist/utils/copyTemplate.d.ts.map +1 -1
- package/dist/utils/copyTemplate.js +98 -4
- package/dist/utils/copyTemplate.js.map +1 -1
- package/dist/utils/updatePackageJson.d.ts +11 -1
- package/dist/utils/updatePackageJson.d.ts.map +1 -1
- package/dist/utils/updatePackageJson.js +12 -10
- package/dist/utils/updatePackageJson.js.map +1 -1
- package/package.json +10 -7
- package/templates/_shared/dev-tools/auth/get-token.js +72 -0
- package/templates/_shared/dev-tools/dev/mock-xrm.js +42 -0
- package/templates/_shared/dev-tools/metadata-sync/index.js +152 -0
- package/templates/_shared/dev-tools/smoke/test-retrieve.js +44 -0
- package/templates/dialog-form/README.md +27 -0
- package/templates/dialog-form/_variants/App.v8.tsx +39 -0
- package/templates/dialog-form/_variants/App.v9.tsx +41 -0
- package/templates/dialog-form/gitignore +5 -0
- package/templates/dialog-form/package.json +27 -0
- package/templates/dialog-form/public/index.html +11 -0
- package/templates/dialog-form/src/index.tsx +10 -0
- package/templates/dialog-form/src/services/dataverse.ts +30 -0
- package/templates/dialog-form/tsconfig.json +15 -0
- package/templates/dialog-form/webpack.config.js +17 -0
- package/templates/grid-customizer/README.md +28 -0
- package/templates/grid-customizer/gitignore +4 -0
- package/templates/grid-customizer/package.json +25 -0
- package/templates/grid-customizer/src/GridCustomizer.ts +28 -0
- package/templates/grid-customizer/src/cell-renderers.tsx +35 -0
- package/templates/grid-customizer/src/index.ts +4 -0
- package/templates/grid-customizer/src/types/grid-types.ts +30 -0
- package/templates/grid-customizer/src/utils/color-utils.ts +24 -0
- package/templates/grid-customizer/tsconfig.json +15 -0
- package/templates/grid-customizer/webpack.config.js +17 -0
- package/templates/pcf-dataset/ControlManifest.Input.xml +16 -0
- package/templates/pcf-dataset/README.md +21 -0
- package/templates/pcf-dataset/gitignore +5 -0
- package/templates/pcf-dataset/index.ts +39 -0
- package/templates/pcf-dataset/package.json +30 -0
- package/templates/pcf-dataset/strings/{{componentName}}.1033.resx +47 -0
- package/templates/pcf-dataset/tsconfig.json +8 -0
- package/templates/pcf-dataset/{{componentName}}Component.tsx +39 -0
- package/templates/pcf-field/ControlManifest.Input.xml +17 -0
- package/templates/pcf-field/README.md +95 -0
- package/templates/pcf-field/_variants/ValueInput.boolean.tsx +24 -0
- package/templates/pcf-field/_variants/ValueInput.date.tsx +27 -0
- package/templates/pcf-field/_variants/ValueInput.number.tsx +35 -0
- package/templates/pcf-field/_variants/ValueInput.text.tsx +27 -0
- package/templates/pcf-field/gitignore +5 -0
- package/templates/pcf-field/index.ts +61 -0
- package/templates/pcf-field/package.json +30 -0
- package/templates/pcf-field/strings/{{componentName}}.1033.resx +47 -0
- package/templates/pcf-field/tsconfig.json +8 -0
- package/templates/pcf-field/{{componentName}}Component.tsx +35 -0
- package/templates/power-pages-starter/gitignore +5 -0
- package/templates/react-custom-page/gitignore +5 -0
- package/templates/{dynamics-365-starter → react-custom-page}/package.json +3 -3
- package/templates/react-custom-page/tools/metadata-sync/index.js +152 -0
- package/templates/static-web-app/README.md +36 -0
- package/templates/static-web-app/_variants/App.v8.tsx +32 -0
- package/templates/static-web-app/_variants/App.v9.tsx +31 -0
- package/templates/static-web-app/api/host.json +12 -0
- package/templates/static-web-app/api/package.json +19 -0
- package/templates/static-web-app/api/src/functions/hello.ts +16 -0
- package/templates/static-web-app/api/tsconfig.json +14 -0
- package/templates/static-web-app/frontend/index.html +12 -0
- package/templates/static-web-app/frontend/package.json +23 -0
- package/templates/static-web-app/frontend/src/index.tsx +8 -0
- package/templates/static-web-app/frontend/tsconfig.json +16 -0
- package/templates/static-web-app/frontend/vite.config.ts +13 -0
- package/templates/static-web-app/gitignore +8 -0
- package/templates/static-web-app/package.json +15 -0
- package/templates/static-web-app/staticwebapp.config.json +7 -0
- package/templates/teams-app/README.md +27 -0
- package/templates/teams-app/_variants/graph.off.ts +7 -0
- package/templates/teams-app/_variants/graph.on.ts +22 -0
- package/templates/teams-app/appPackage/manifest.json +26 -0
- package/templates/teams-app/gitignore +5 -0
- package/templates/teams-app/index.html +12 -0
- package/templates/teams-app/package.json +26 -0
- package/templates/teams-app/src/App.tsx +25 -0
- package/templates/teams-app/src/index.tsx +8 -0
- package/templates/teams-app/tsconfig.json +16 -0
- package/templates/teams-app/vite.config.ts +9 -0
- package/templates/web-resource/README.md +39 -0
- package/templates/web-resource/_variants/App.v8.tsx +29 -0
- package/templates/web-resource/_variants/App.v9.tsx +28 -0
- package/templates/web-resource/gitignore +5 -0
- package/templates/web-resource/package.json +27 -0
- package/templates/web-resource/public/index.html +11 -0
- package/templates/web-resource/src/index.tsx +10 -0
- package/templates/web-resource/src/services/dataverse.ts +30 -0
- package/templates/web-resource/tsconfig.json +15 -0
- package/templates/web-resource/webpack.config.js +17 -0
- package/dist/utils/consultingHelpers.d.ts +0 -13
- package/dist/utils/consultingHelpers.d.ts.map +0 -1
- package/dist/utils/consultingHelpers.js +0 -569
- package/dist/utils/consultingHelpers.js.map +0 -1
- package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +0 -302
- package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +0 -305
- package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +0 -507
- package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +0 -372
- package/templates/dynamics-365-starter/deployment/pipelines/README.md +0 -375
- package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +0 -330
- package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +0 -422
- package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +0 -636
- package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +0 -417
- package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +0 -582
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +0 -486
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +0 -567
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +0 -703
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +0 -671
- package/templates/dynamics-365-starter/docs/team-standards/README.md +0 -273
- package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +0 -577
- package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +0 -359
- package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +0 -700
- package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +0 -736
- package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +0 -727
- package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +0 -758
- package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +0 -878
- package/templates/dynamics-365-starter/src/client-project-template/README.md +0 -234
- package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +0 -114
- package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +0 -186
- package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +0 -667
- package/templates/dynamics-365-starter/src/examples/README.md +0 -52
- package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +0 -625
- package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +0 -545
- package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +0 -722
- package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +0 -662
- package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +0 -519
- package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +0 -456
- package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +0 -406
- package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +0 -578
- package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +0 -629
- package/templates/dynamics-365-starter/tools/entity-generator/index.js +0 -168
- package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +0 -124
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +0 -283
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +0 -275
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +0 -204
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +0 -413
- package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +0 -250
- package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +0 -410
- package/templates/dynamics-365-starter/tools/metadata-sync/index.js +0 -512
- package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +0 -675
- /package/templates/{dynamics-365-starter → react-custom-page}/README.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/deployment/README.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/ARCHITECTURE_OVERVIEW.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/BEST_PRACTICES.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/MIGRATION_GUIDE.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/public/index.html +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/scripts/custom-build.js +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LogDialog.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingContext.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingProvider.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/logger.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/account.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/contact.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/index.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Account.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/BaseEntity.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Contact.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/ContactControlWrapper.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/MultiEntityControlWrapper.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/providers/DynamicsProvider.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/MockApiService.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/ServiceFactory.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/XrmApiService.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/styles/index.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/tsconfig.json +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/webpack.config.js +0 -0
|
@@ -1,675 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript Type Generator for Dynamics 365 Entities
|
|
3
|
-
* Converts D365 metadata to TypeScript interfaces and constants
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs-extra');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
class TypeScriptGenerator {
|
|
10
|
-
constructor(options = {}) {
|
|
11
|
-
this.options = {
|
|
12
|
-
generateInterfaces: true,
|
|
13
|
-
generateConstants: true,
|
|
14
|
-
generateValidators: true,
|
|
15
|
-
generateHelpers: true,
|
|
16
|
-
strictNullChecks: true,
|
|
17
|
-
includeComments: true,
|
|
18
|
-
exportAll: true,
|
|
19
|
-
...options,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Generate all TypeScript files for an entity
|
|
25
|
-
*/
|
|
26
|
-
async generateEntityFiles(entityMetadata, outputDir) {
|
|
27
|
-
const entityName = entityMetadata.LogicalName;
|
|
28
|
-
const results = {};
|
|
29
|
-
|
|
30
|
-
if (this.options.generateInterfaces) {
|
|
31
|
-
const interfaceContent = this.generateInterfaceFile(entityMetadata);
|
|
32
|
-
const interfacePath = path.join(outputDir, `${entityName}.interface.ts`);
|
|
33
|
-
await fs.writeFile(interfacePath, interfaceContent);
|
|
34
|
-
results.interface = interfacePath;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (this.options.generateConstants) {
|
|
38
|
-
const constantsContent = this.generateConstantsFile(entityMetadata);
|
|
39
|
-
const constantsPath = path.join(outputDir, `${entityName}.constants.ts`);
|
|
40
|
-
await fs.writeFile(constantsPath, constantsContent);
|
|
41
|
-
results.constants = constantsPath;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (this.options.generateValidators) {
|
|
45
|
-
const validatorContent = this.generateValidatorFile(entityMetadata);
|
|
46
|
-
const validatorPath = path.join(outputDir, `${entityName}.validator.ts`);
|
|
47
|
-
await fs.writeFile(validatorPath, validatorContent);
|
|
48
|
-
results.validator = validatorPath;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (this.options.generateHelpers) {
|
|
52
|
-
const helperContent = this.generateHelperFile(entityMetadata);
|
|
53
|
-
const helperPath = path.join(outputDir, `${entityName}.helpers.ts`);
|
|
54
|
-
await fs.writeFile(helperPath, helperContent);
|
|
55
|
-
results.helpers = helperPath;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return results;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Generate TypeScript interface file
|
|
63
|
-
*/
|
|
64
|
-
generateInterfaceFile(metadata) {
|
|
65
|
-
const interfaceName = `I${metadata.SchemaName}`;
|
|
66
|
-
const attributes = metadata.Attributes || [];
|
|
67
|
-
|
|
68
|
-
let content = this.generateFileHeader(metadata, 'Interface definitions');
|
|
69
|
-
|
|
70
|
-
// Import statements
|
|
71
|
-
content += this.generateImports(metadata);
|
|
72
|
-
|
|
73
|
-
// Main interface
|
|
74
|
-
content += this.generateMainInterface(interfaceName, attributes, metadata);
|
|
75
|
-
|
|
76
|
-
// Create interface (without system fields)
|
|
77
|
-
content += this.generateCreateInterface(
|
|
78
|
-
interfaceName,
|
|
79
|
-
attributes,
|
|
80
|
-
metadata
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
// Update interface (partial, without system fields)
|
|
84
|
-
content += this.generateUpdateInterface(
|
|
85
|
-
interfaceName,
|
|
86
|
-
attributes,
|
|
87
|
-
metadata
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
// Response interface (with OData annotations)
|
|
91
|
-
content += this.generateResponseInterface(
|
|
92
|
-
interfaceName,
|
|
93
|
-
attributes,
|
|
94
|
-
metadata
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// Lookup interfaces for related entities
|
|
98
|
-
content += this.generateLookupInterfaces(metadata);
|
|
99
|
-
|
|
100
|
-
return content;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Generate constants file
|
|
105
|
-
*/
|
|
106
|
-
generateConstantsFile(metadata) {
|
|
107
|
-
const className = `${metadata.SchemaName}Constants`;
|
|
108
|
-
const attributes = metadata.Attributes || [];
|
|
109
|
-
|
|
110
|
-
let content = this.generateFileHeader(metadata, 'Constants and metadata');
|
|
111
|
-
|
|
112
|
-
// Class definition
|
|
113
|
-
content += `export class ${className} {\n`;
|
|
114
|
-
|
|
115
|
-
// Entity metadata
|
|
116
|
-
content += this.generateEntityMetadata(metadata);
|
|
117
|
-
|
|
118
|
-
// Attribute constants
|
|
119
|
-
content += this.generateAttributeConstants(attributes);
|
|
120
|
-
|
|
121
|
-
// Option set constants
|
|
122
|
-
content += this.generateOptionSetConstants(attributes);
|
|
123
|
-
|
|
124
|
-
// Relationship constants
|
|
125
|
-
content += this.generateRelationshipConstants(metadata);
|
|
126
|
-
|
|
127
|
-
// Display names
|
|
128
|
-
content += this.generateDisplayNames(attributes);
|
|
129
|
-
|
|
130
|
-
// Required fields
|
|
131
|
-
content += this.generateRequiredFields(attributes);
|
|
132
|
-
|
|
133
|
-
// Field collections
|
|
134
|
-
content += this.generateFieldCollections(attributes);
|
|
135
|
-
|
|
136
|
-
content += '}\n';
|
|
137
|
-
|
|
138
|
-
return content;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Generate validator file
|
|
143
|
-
*/
|
|
144
|
-
generateValidatorFile(metadata) {
|
|
145
|
-
const interfaceName = `I${metadata.SchemaName}`;
|
|
146
|
-
const validatorName = `${metadata.SchemaName}Validator`;
|
|
147
|
-
const attributes = metadata.Attributes || [];
|
|
148
|
-
|
|
149
|
-
let content = this.generateFileHeader(metadata, 'Validation functions');
|
|
150
|
-
|
|
151
|
-
// Import statements
|
|
152
|
-
content += `import { ${interfaceName}, ${interfaceName}Create, ${interfaceName}Update } from './${metadata.LogicalName}.interface';\n`;
|
|
153
|
-
content += `import { ${metadata.SchemaName}Constants } from './${metadata.LogicalName}.constants';\n\n`;
|
|
154
|
-
|
|
155
|
-
// Validation result interface
|
|
156
|
-
content += this.generateValidationResultInterface();
|
|
157
|
-
|
|
158
|
-
// Main validator class
|
|
159
|
-
content += this.generateValidatorClass(
|
|
160
|
-
validatorName,
|
|
161
|
-
interfaceName,
|
|
162
|
-
attributes,
|
|
163
|
-
metadata
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
return content;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Generate helper file
|
|
171
|
-
*/
|
|
172
|
-
generateHelperFile(metadata) {
|
|
173
|
-
const interfaceName = `I${metadata.SchemaName}`;
|
|
174
|
-
const helperName = `${metadata.SchemaName}Helper`;
|
|
175
|
-
|
|
176
|
-
let content = this.generateFileHeader(
|
|
177
|
-
metadata,
|
|
178
|
-
'Helper functions and utilities'
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
// Import statements
|
|
182
|
-
content += `import { ${interfaceName} } from './${metadata.LogicalName}.interface';\n`;
|
|
183
|
-
content += `import { ${metadata.SchemaName}Constants } from './${metadata.LogicalName}.constants';\n\n`;
|
|
184
|
-
|
|
185
|
-
// Helper class
|
|
186
|
-
content += this.generateHelperClass(helperName, interfaceName, metadata);
|
|
187
|
-
|
|
188
|
-
return content;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Generate file header with metadata
|
|
193
|
-
*/
|
|
194
|
-
generateFileHeader(metadata, description) {
|
|
195
|
-
if (!this.options.includeComments) return '';
|
|
196
|
-
|
|
197
|
-
return `/**
|
|
198
|
-
* Auto-generated ${description} for ${metadata.DisplayName} entity
|
|
199
|
-
*
|
|
200
|
-
* Entity: ${metadata.LogicalName} (${metadata.SchemaName})
|
|
201
|
-
* Generated: ${new Date().toISOString()}
|
|
202
|
-
* Source: ${metadata.Metadata?.SyncedFrom || 'Dynamics 365'}
|
|
203
|
-
*
|
|
204
|
-
* @warning This file is auto-generated. Do not modify manually.
|
|
205
|
-
* Re-run the metadata sync to update this file.
|
|
206
|
-
*/
|
|
207
|
-
|
|
208
|
-
`;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Generate import statements
|
|
213
|
-
*/
|
|
214
|
-
generateImports(metadata) {
|
|
215
|
-
let imports = '';
|
|
216
|
-
|
|
217
|
-
// Check if we need Date type imports
|
|
218
|
-
const hasDateFields = metadata.Attributes?.some(
|
|
219
|
-
(attr) => attr.AttributeType === 'DateTime'
|
|
220
|
-
);
|
|
221
|
-
if (hasDateFields) {
|
|
222
|
-
imports += '// Note: Date fields are represented as Date objects\n';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Check if we need lookup type imports
|
|
226
|
-
const hasLookupFields = metadata.Attributes?.some((attr) =>
|
|
227
|
-
['Lookup', 'Customer', 'Owner'].includes(attr.AttributeType)
|
|
228
|
-
);
|
|
229
|
-
if (hasLookupFields) {
|
|
230
|
-
imports += '// Lookup fields reference related entity IDs\n';
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (imports) {
|
|
234
|
-
imports += '\n';
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return imports;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Generate main interface
|
|
242
|
-
*/
|
|
243
|
-
generateMainInterface(interfaceName, attributes, metadata) {
|
|
244
|
-
let content = `export interface ${interfaceName} {\n`;
|
|
245
|
-
|
|
246
|
-
attributes.forEach((attr) => {
|
|
247
|
-
const tsType = this.mapAttributeToTypeScript(attr);
|
|
248
|
-
const isOptional = this.isAttributeOptional(attr);
|
|
249
|
-
const optionalMarker = isOptional ? '?' : '';
|
|
250
|
-
|
|
251
|
-
if (this.options.includeComments) {
|
|
252
|
-
content += ` /** ${attr.DisplayName}`;
|
|
253
|
-
if (attr.AttributeType) content += ` - Type: ${attr.AttributeType}`;
|
|
254
|
-
if (attr.MaxLength) content += `, MaxLength: ${attr.MaxLength}`;
|
|
255
|
-
if (attr.RequiredLevel) content += `, Required: ${attr.RequiredLevel}`;
|
|
256
|
-
content += ' */\n';
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
content += ` ${attr.LogicalName}${optionalMarker}: ${tsType};\n\n`;
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
content += '}\n\n';
|
|
263
|
-
return content;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Generate create interface (omits system fields)
|
|
268
|
-
*/
|
|
269
|
-
generateCreateInterface(interfaceName, attributes, metadata) {
|
|
270
|
-
const systemFields = [
|
|
271
|
-
metadata.PrimaryIdAttribute,
|
|
272
|
-
'createdon',
|
|
273
|
-
'modifiedon',
|
|
274
|
-
'createdby',
|
|
275
|
-
'modifiedby',
|
|
276
|
-
'versionnumber',
|
|
277
|
-
'ownerid', // Usually set by system
|
|
278
|
-
];
|
|
279
|
-
|
|
280
|
-
const omitFields = systemFields
|
|
281
|
-
.filter((field) => attributes.some((attr) => attr.LogicalName === field))
|
|
282
|
-
.join(' | ');
|
|
283
|
-
|
|
284
|
-
let content = `export interface ${interfaceName}Create`;
|
|
285
|
-
|
|
286
|
-
if (omitFields) {
|
|
287
|
-
content += ` extends Omit<${interfaceName}, '${omitFields.replace(' | ', "' | '")}'`;
|
|
288
|
-
} else {
|
|
289
|
-
content += ` extends ${interfaceName}`;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
content += ' {}\n\n';
|
|
293
|
-
return content;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Generate update interface (partial)
|
|
298
|
-
*/
|
|
299
|
-
generateUpdateInterface(interfaceName, attributes, metadata) {
|
|
300
|
-
const systemFields = [
|
|
301
|
-
metadata.PrimaryIdAttribute,
|
|
302
|
-
'createdon',
|
|
303
|
-
'modifiedon',
|
|
304
|
-
'createdby',
|
|
305
|
-
'modifiedby',
|
|
306
|
-
'versionnumber',
|
|
307
|
-
];
|
|
308
|
-
|
|
309
|
-
const omitFields = systemFields
|
|
310
|
-
.filter((field) => attributes.some((attr) => attr.LogicalName === field))
|
|
311
|
-
.join(' | ');
|
|
312
|
-
|
|
313
|
-
let content = `export interface ${interfaceName}Update extends Partial<`;
|
|
314
|
-
|
|
315
|
-
if (omitFields) {
|
|
316
|
-
content += `Omit<${interfaceName}, '${omitFields.replace(' | ', "' | '")}'>`;
|
|
317
|
-
} else {
|
|
318
|
-
content += interfaceName;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
content += '> {}\n\n';
|
|
322
|
-
return content;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Generate response interface with OData annotations
|
|
327
|
-
*/
|
|
328
|
-
generateResponseInterface(interfaceName, attributes, metadata) {
|
|
329
|
-
let content = `export interface ${interfaceName}Response extends ${interfaceName} {\n`;
|
|
330
|
-
content += ` '@odata.etag'?: string;\n`;
|
|
331
|
-
content += ` '@odata.context'?: string;\n`;
|
|
332
|
-
|
|
333
|
-
// Add navigation properties
|
|
334
|
-
const relationships = [
|
|
335
|
-
...(metadata.OneToManyRelationships || []),
|
|
336
|
-
...(metadata.ManyToOneRelationships || []),
|
|
337
|
-
];
|
|
338
|
-
|
|
339
|
-
relationships.forEach((rel) => {
|
|
340
|
-
if (this.options.includeComments) {
|
|
341
|
-
content += ` /** Navigation property: ${rel.SchemaName} */\n`;
|
|
342
|
-
}
|
|
343
|
-
content += ` '${rel.SchemaName}'?: any; // Navigation property\n`;
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
content += '}\n\n';
|
|
347
|
-
return content;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Generate lookup interfaces
|
|
352
|
-
*/
|
|
353
|
-
generateLookupInterfaces(metadata) {
|
|
354
|
-
const lookupFields =
|
|
355
|
-
metadata.Attributes?.filter((attr) =>
|
|
356
|
-
['Lookup', 'Customer', 'Owner'].includes(attr.AttributeType)
|
|
357
|
-
) || [];
|
|
358
|
-
|
|
359
|
-
if (lookupFields.length === 0) return '';
|
|
360
|
-
|
|
361
|
-
let content = '// Lookup field interfaces\n';
|
|
362
|
-
|
|
363
|
-
lookupFields.forEach((field) => {
|
|
364
|
-
const interfaceName = `${metadata.SchemaName}${field.SchemaName}Lookup`;
|
|
365
|
-
|
|
366
|
-
content += `export interface ${interfaceName} {\n`;
|
|
367
|
-
content += ` ${field.LogicalName}: string; // Entity ID\n`;
|
|
368
|
-
content += ` '${field.LogicalName}@OData.Community.Display.V1.FormattedValue'?: string; // Display name\n`;
|
|
369
|
-
content += ` '${field.LogicalName}@Microsoft.Dynamics.CRM.lookuplogicalname'?: string; // Entity type\n`;
|
|
370
|
-
content += '}\n\n';
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
return content;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Generate entity metadata constants
|
|
378
|
-
*/
|
|
379
|
-
generateEntityMetadata(metadata) {
|
|
380
|
-
let content = ' // Entity Metadata\n';
|
|
381
|
-
content += ` public static readonly LogicalName = '${metadata.LogicalName}';\n`;
|
|
382
|
-
content += ` public static readonly SchemaName = '${metadata.SchemaName}';\n`;
|
|
383
|
-
content += ` public static readonly EntitySetName = '${metadata.EntitySetName}';\n`;
|
|
384
|
-
content += ` public static readonly DisplayName = '${metadata.DisplayName}';\n`;
|
|
385
|
-
content += ` public static readonly PrimaryIdAttribute = '${metadata.PrimaryIdAttribute}';\n`;
|
|
386
|
-
content += ` public static readonly PrimaryNameAttribute = '${metadata.PrimaryNameAttribute}';\n`;
|
|
387
|
-
content += ` public static readonly IsCustomEntity = ${metadata.IsCustomEntity};\n\n`;
|
|
388
|
-
return content;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Generate attribute constants
|
|
393
|
-
*/
|
|
394
|
-
generateAttributeConstants(attributes) {
|
|
395
|
-
let content = ' // Attribute Names\n';
|
|
396
|
-
|
|
397
|
-
attributes.forEach((attr) => {
|
|
398
|
-
if (this.options.includeComments) {
|
|
399
|
-
content += ` /** ${attr.DisplayName} - Type: ${attr.AttributeType}`;
|
|
400
|
-
if (attr.RequiredLevel) content += `, Required: ${attr.RequiredLevel}`;
|
|
401
|
-
if (attr.MaxLength) content += `, MaxLength: ${attr.MaxLength}`;
|
|
402
|
-
content += ' */\n';
|
|
403
|
-
}
|
|
404
|
-
content += ` public static readonly ${attr.SchemaName} = '${attr.LogicalName}';\n`;
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
content += '\n';
|
|
408
|
-
return content;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Generate option set constants
|
|
413
|
-
*/
|
|
414
|
-
generateOptionSetConstants(attributes) {
|
|
415
|
-
const optionSetFields = attributes.filter((attr) =>
|
|
416
|
-
['Picklist', 'State', 'Status', 'MultiSelectPicklist'].includes(
|
|
417
|
-
attr.AttributeType
|
|
418
|
-
)
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
if (optionSetFields.length === 0) return '';
|
|
422
|
-
|
|
423
|
-
let content = ' // Option Set Values\n';
|
|
424
|
-
|
|
425
|
-
optionSetFields.forEach((field) => {
|
|
426
|
-
content += ` public static readonly ${field.SchemaName}Options = {\n`;
|
|
427
|
-
content += ` // TODO: Add actual option values from metadata\n`;
|
|
428
|
-
content += ` // Sync with: npm run metadata:sync-optionsets\n`;
|
|
429
|
-
content += ' } as const;\n\n';
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
return content;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Generate relationship constants
|
|
437
|
-
*/
|
|
438
|
-
generateRelationshipConstants(metadata) {
|
|
439
|
-
const relationships = [
|
|
440
|
-
...(metadata.OneToManyRelationships || []),
|
|
441
|
-
...(metadata.ManyToOneRelationships || []),
|
|
442
|
-
];
|
|
443
|
-
|
|
444
|
-
if (relationships.length === 0) return '';
|
|
445
|
-
|
|
446
|
-
let content = ' // Relationship Names\n';
|
|
447
|
-
|
|
448
|
-
relationships.forEach((rel) => {
|
|
449
|
-
content += ` public static readonly ${rel.SchemaName} = '${rel.SchemaName}';\n`;
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
content += '\n';
|
|
453
|
-
return content;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Generate display names object
|
|
458
|
-
*/
|
|
459
|
-
generateDisplayNames(attributes) {
|
|
460
|
-
let content = ' // Display Names for UI\n';
|
|
461
|
-
content += ' public static readonly FieldDisplayNames = {\n';
|
|
462
|
-
|
|
463
|
-
attributes.forEach((attr) => {
|
|
464
|
-
content += ` [this.${attr.SchemaName}]: '${attr.DisplayName}',\n`;
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
content += ' } as const;\n\n';
|
|
468
|
-
return content;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Generate required fields array
|
|
473
|
-
*/
|
|
474
|
-
generateRequiredFields(attributes) {
|
|
475
|
-
const requiredFields = attributes.filter(
|
|
476
|
-
(attr) =>
|
|
477
|
-
attr.RequiredLevel === 'ApplicationRequired' ||
|
|
478
|
-
attr.RequiredLevel === 'SystemRequired'
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
let content = ' // Required Fields\n';
|
|
482
|
-
content += ' public static readonly RequiredFields = [\n';
|
|
483
|
-
|
|
484
|
-
requiredFields.forEach((field) => {
|
|
485
|
-
content += ` this.${field.SchemaName},\n`;
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
content += ' ] as const;\n\n';
|
|
489
|
-
return content;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* Generate field collections
|
|
494
|
-
*/
|
|
495
|
-
generateFieldCollections(attributes) {
|
|
496
|
-
let content = ' // Field Collections for different operations\n';
|
|
497
|
-
|
|
498
|
-
// Create fields (exclude system fields)
|
|
499
|
-
const createFields = attributes.filter(
|
|
500
|
-
(attr) => attr.IsValidForCreate && !attr.IsPrimaryId
|
|
501
|
-
);
|
|
502
|
-
content += ' public static readonly CreateFields = [\n';
|
|
503
|
-
createFields.forEach((field) => {
|
|
504
|
-
content += ` this.${field.SchemaName},\n`;
|
|
505
|
-
});
|
|
506
|
-
content += ' ] as const;\n\n';
|
|
507
|
-
|
|
508
|
-
// Update fields
|
|
509
|
-
const updateFields = attributes.filter((attr) => attr.IsValidForUpdate);
|
|
510
|
-
content += ' public static readonly UpdateFields = [\n';
|
|
511
|
-
updateFields.forEach((field) => {
|
|
512
|
-
content += ` this.${field.SchemaName},\n`;
|
|
513
|
-
});
|
|
514
|
-
content += ' ] as const;\n\n';
|
|
515
|
-
|
|
516
|
-
return content;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* Generate validation result interface
|
|
521
|
-
*/
|
|
522
|
-
generateValidationResultInterface() {
|
|
523
|
-
return `export interface ValidationResult {
|
|
524
|
-
isValid: boolean;
|
|
525
|
-
errors: ValidationError[];
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
export interface ValidationError {
|
|
529
|
-
field: string;
|
|
530
|
-
message: string;
|
|
531
|
-
value?: any;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
`;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Generate validator class
|
|
539
|
-
*/
|
|
540
|
-
generateValidatorClass(validatorName, interfaceName, attributes, metadata) {
|
|
541
|
-
let content = `export class ${validatorName} {\n`;
|
|
542
|
-
|
|
543
|
-
// Validate create method
|
|
544
|
-
content += ` public static validateCreate(data: ${interfaceName}Create): ValidationResult {\n`;
|
|
545
|
-
content += ' const errors: ValidationError[] = [];\n\n';
|
|
546
|
-
|
|
547
|
-
// Required field validation
|
|
548
|
-
const requiredFields = attributes.filter(
|
|
549
|
-
(attr) =>
|
|
550
|
-
attr.RequiredLevel === 'ApplicationRequired' && attr.IsValidForCreate
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
requiredFields.forEach((field) => {
|
|
554
|
-
content += ` if (!data.${field.LogicalName}) {\n`;
|
|
555
|
-
content += ` errors.push({\n`;
|
|
556
|
-
content += ` field: '${field.LogicalName}',\n`;
|
|
557
|
-
content += ` message: '${field.DisplayName} is required',\n`;
|
|
558
|
-
content += ` value: data.${field.LogicalName}\n`;
|
|
559
|
-
content += ' });\n';
|
|
560
|
-
content += ' }\n\n';
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
// String length validation
|
|
564
|
-
const stringFields = attributes.filter(
|
|
565
|
-
(attr) => attr.AttributeType === 'String' && attr.MaxLength
|
|
566
|
-
);
|
|
567
|
-
|
|
568
|
-
stringFields.forEach((field) => {
|
|
569
|
-
content += ` if (data.${field.LogicalName} && data.${field.LogicalName}.length > ${field.MaxLength}) {\n`;
|
|
570
|
-
content += ` errors.push({\n`;
|
|
571
|
-
content += ` field: '${field.LogicalName}',\n`;
|
|
572
|
-
content += ` message: '${field.DisplayName} cannot exceed ${field.MaxLength} characters',\n`;
|
|
573
|
-
content += ` value: data.${field.LogicalName}\n`;
|
|
574
|
-
content += ' });\n';
|
|
575
|
-
content += ' }\n\n';
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
content += ' return { isValid: errors.length === 0, errors };\n';
|
|
579
|
-
content += ' }\n\n';
|
|
580
|
-
|
|
581
|
-
// Validate update method
|
|
582
|
-
content += ` public static validateUpdate(data: ${interfaceName}Update): ValidationResult {\n`;
|
|
583
|
-
content += ' const errors: ValidationError[] = [];\n\n';
|
|
584
|
-
content += ' // Add update-specific validation logic here\n\n';
|
|
585
|
-
content += ' return { isValid: errors.length === 0, errors };\n';
|
|
586
|
-
content += ' }\n';
|
|
587
|
-
|
|
588
|
-
content += '}\n\n';
|
|
589
|
-
return content;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
/**
|
|
593
|
-
* Generate helper class
|
|
594
|
-
*/
|
|
595
|
-
generateHelperClass(helperName, interfaceName, metadata) {
|
|
596
|
-
let content = `export class ${helperName} {\n`;
|
|
597
|
-
|
|
598
|
-
// Format display name method
|
|
599
|
-
content += ` public static getDisplayName(entity: ${interfaceName}): string {\n`;
|
|
600
|
-
content += ` return entity.${metadata.PrimaryNameAttribute} || 'Unnamed ${metadata.DisplayName}';\n`;
|
|
601
|
-
content += ' }\n\n';
|
|
602
|
-
|
|
603
|
-
// Convert to display object method
|
|
604
|
-
content += ` public static toDisplayObject(entity: ${interfaceName}): Record<string, string> {\n`;
|
|
605
|
-
content += ' return {\n';
|
|
606
|
-
content += ` id: entity.${metadata.PrimaryIdAttribute} || '',\n`;
|
|
607
|
-
content += ` name: this.getDisplayName(entity),\n`;
|
|
608
|
-
content += ' // Add other commonly displayed fields here\n';
|
|
609
|
-
content += ' };\n';
|
|
610
|
-
content += ' }\n\n';
|
|
611
|
-
|
|
612
|
-
// Convert to create data method
|
|
613
|
-
content += ` public static toCreateData(entity: ${interfaceName}): ${interfaceName}Create {\n`;
|
|
614
|
-
content += ' const createData: any = {};\n\n';
|
|
615
|
-
content += ` ${metadata.SchemaName}Constants.CreateFields.forEach(field => {\n`;
|
|
616
|
-
content += ' if (entity[field] !== undefined) {\n';
|
|
617
|
-
content += ' createData[field] = entity[field];\n';
|
|
618
|
-
content += ' }\n';
|
|
619
|
-
content += ' });\n\n';
|
|
620
|
-
content += ' return createData;\n';
|
|
621
|
-
content += ' }\n';
|
|
622
|
-
|
|
623
|
-
content += '}\n\n';
|
|
624
|
-
return content;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Map D365 attribute type to TypeScript type
|
|
629
|
-
*/
|
|
630
|
-
mapAttributeToTypeScript(attribute) {
|
|
631
|
-
const typeMap = {
|
|
632
|
-
String: 'string',
|
|
633
|
-
Memo: 'string',
|
|
634
|
-
Integer: 'number',
|
|
635
|
-
BigInt: 'number',
|
|
636
|
-
Double: 'number',
|
|
637
|
-
Decimal: 'number',
|
|
638
|
-
Money: 'number',
|
|
639
|
-
Boolean: 'boolean',
|
|
640
|
-
DateTime: 'Date',
|
|
641
|
-
Uniqueidentifier: 'string',
|
|
642
|
-
Picklist: 'number',
|
|
643
|
-
State: 'number',
|
|
644
|
-
Status: 'number',
|
|
645
|
-
Lookup: 'string',
|
|
646
|
-
Customer: 'string',
|
|
647
|
-
Owner: 'string',
|
|
648
|
-
MultiSelectPicklist: 'number[]',
|
|
649
|
-
Virtual: 'any',
|
|
650
|
-
EntityName: 'string',
|
|
651
|
-
ManagedProperty: 'boolean',
|
|
652
|
-
};
|
|
653
|
-
|
|
654
|
-
const baseType = typeMap[attribute.AttributeType] || 'unknown';
|
|
655
|
-
|
|
656
|
-
// Add null union if nullable
|
|
657
|
-
if (this.options.strictNullChecks && this.isAttributeOptional(attribute)) {
|
|
658
|
-
return `${baseType} | null`;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
return baseType;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* Determine if attribute is optional
|
|
666
|
-
*/
|
|
667
|
-
isAttributeOptional(attribute) {
|
|
668
|
-
return (
|
|
669
|
-
attribute.RequiredLevel !== 'ApplicationRequired' &&
|
|
670
|
-
attribute.RequiredLevel !== 'SystemRequired'
|
|
671
|
-
);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
module.exports = { TypeScriptGenerator };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.css
RENAMED
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.tsx
RENAMED
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.css
RENAMED
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.tsx
RENAMED
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.css
RENAMED
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.tsx
RENAMED
|
File without changes
|
/package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.css
RENAMED
|
File without changes
|