@microsoft/power-apps-cli 0.5.4 → 0.5.7

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.
Files changed (138) hide show
  1. package/lib/Constants/HelpStrings.d.ts +3 -3
  2. package/lib/Constants/HelpStrings.js +3 -3
  3. package/lib/Constants/HelpStrings.js.map +1 -1
  4. package/lib/HttpClient/CliHttpClient.d.ts.map +1 -1
  5. package/lib/HttpClient/CliHttpClient.js +8 -1
  6. package/lib/HttpClient/CliHttpClient.js.map +1 -1
  7. package/lib/Verbs/AddDataSource.d.ts.map +1 -1
  8. package/lib/Verbs/AddDataSource.js +7 -6
  9. package/lib/Verbs/AddDataSource.js.map +1 -1
  10. package/lib/Verbs/DeleteDataSource.d.ts +1 -1
  11. package/lib/Verbs/DeleteDataSource.d.ts.map +1 -1
  12. package/lib/Verbs/DeleteDataSource.js +2 -1
  13. package/lib/Verbs/DeleteDataSource.js.map +1 -1
  14. package/lib/Verbs/ListConnectionReferences.js +6 -6
  15. package/lib/Verbs/ListConnectionReferences.js.map +1 -1
  16. package/lib/Verbs/ListEnvironmentVariables.js +6 -6
  17. package/lib/Verbs/ListEnvironmentVariables.js.map +1 -1
  18. package/lib/Verbs/Push.js +7 -10
  19. package/lib/Verbs/Push.js.map +1 -1
  20. package/lib/Verbs/VerbConstants.d.ts +1 -1
  21. package/lib/Verbs/VerbConstants.js +3 -3
  22. package/lib/Verbs/VerbConstants.js.map +1 -1
  23. package/lib/__tests__/E2eTests/addAndDeleteDataverseDS.test.js +4 -3
  24. package/lib/__tests__/E2eTests/addAndDeleteDataverseDS.test.js.map +1 -1
  25. package/lib/__tests__/E2eTests/addTop10Datasources.test.js +3 -2
  26. package/lib/__tests__/E2eTests/addTop10Datasources.test.js.map +1 -1
  27. package/lib/__tests__/E2eTests/cliHelp.test.js +4 -11
  28. package/lib/__tests__/E2eTests/cliHelp.test.js.map +1 -1
  29. package/lib/__tests__/helpers/e2eTestHelpers.d.ts +24 -0
  30. package/lib/__tests__/helpers/e2eTestHelpers.d.ts.map +1 -0
  31. package/lib/__tests__/helpers/e2eTestHelpers.js +28 -0
  32. package/lib/__tests__/helpers/e2eTestHelpers.js.map +1 -0
  33. package/lib-cjs/Constants/HelpStrings.d.ts +3 -3
  34. package/lib-cjs/Constants/HelpStrings.js +3 -3
  35. package/lib-cjs/Constants/HelpStrings.js.map +1 -1
  36. package/lib-cjs/HttpClient/CliHttpClient.d.ts.map +1 -1
  37. package/lib-cjs/HttpClient/CliHttpClient.js +8 -2
  38. package/lib-cjs/HttpClient/CliHttpClient.js.map +1 -1
  39. package/lib-cjs/Verbs/AddDataSource.d.ts.map +1 -1
  40. package/lib-cjs/Verbs/AddDataSource.js +7 -6
  41. package/lib-cjs/Verbs/AddDataSource.js.map +1 -1
  42. package/lib-cjs/Verbs/DeleteDataSource.d.ts +1 -1
  43. package/lib-cjs/Verbs/DeleteDataSource.d.ts.map +1 -1
  44. package/lib-cjs/Verbs/DeleteDataSource.js +5 -1
  45. package/lib-cjs/Verbs/DeleteDataSource.js.map +1 -1
  46. package/lib-cjs/Verbs/ListConnectionReferences.js +6 -6
  47. package/lib-cjs/Verbs/ListConnectionReferences.js.map +1 -1
  48. package/lib-cjs/Verbs/ListEnvironmentVariables.js +6 -6
  49. package/lib-cjs/Verbs/ListEnvironmentVariables.js.map +1 -1
  50. package/lib-cjs/Verbs/Push.js +11 -16
  51. package/lib-cjs/Verbs/Push.js.map +1 -1
  52. package/lib-cjs/Verbs/VerbConstants.d.ts +1 -1
  53. package/lib-cjs/Verbs/VerbConstants.js +3 -3
  54. package/lib-cjs/Verbs/VerbConstants.js.map +1 -1
  55. package/lib-cjs/__tests__/E2eTests/addAndDeleteDataverseDS.test.js +3 -2
  56. package/lib-cjs/__tests__/E2eTests/addAndDeleteDataverseDS.test.js.map +1 -1
  57. package/lib-cjs/__tests__/E2eTests/addTop10Datasources.test.js +2 -1
  58. package/lib-cjs/__tests__/E2eTests/addTop10Datasources.test.js.map +1 -1
  59. package/lib-cjs/__tests__/E2eTests/cliHelp.test.js +4 -11
  60. package/lib-cjs/__tests__/E2eTests/cliHelp.test.js.map +1 -1
  61. package/lib-cjs/__tests__/helpers/e2eTestHelpers.d.ts +23 -0
  62. package/lib-cjs/__tests__/helpers/e2eTestHelpers.d.ts.map +1 -0
  63. package/lib-cjs/__tests__/helpers/e2eTestHelpers.js +31 -0
  64. package/lib-cjs/__tests__/helpers/e2eTestHelpers.js.map +1 -0
  65. package/node_modules/@microsoft/powerapps-data/package.json +2 -2
  66. package/node_modules/@microsoft/powerapps-player-actions/lib/Actions/PushApp.js +10 -3
  67. package/node_modules/@microsoft/powerapps-player-actions/lib/Actions/PushApp.js.map +1 -1
  68. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/codeGenUtils.d.ts +20 -0
  69. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/codeGenUtils.d.ts.map +1 -1
  70. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/codeGenUtils.js +79 -0
  71. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/codeGenUtils.js.map +1 -1
  72. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/dataSourceInfoProcessor.d.ts +2 -2
  73. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/dataSourceInfoProcessor.d.ts.map +1 -1
  74. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/dataSourceInfoProcessor.js +27 -68
  75. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/dataSourceInfoProcessor.js.map +1 -1
  76. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/modelServiceGenerator.d.ts +0 -59
  77. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/modelServiceGenerator.d.ts.map +1 -1
  78. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/modelServiceGenerator.js +69 -281
  79. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/modelServiceGenerator.js.map +1 -1
  80. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/nameUtility.d.ts +26 -0
  81. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/nameUtility.d.ts.map +1 -1
  82. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/nameUtility.js +153 -0
  83. package/node_modules/@microsoft/powerapps-player-actions/lib/CodeGen/nameUtility.js.map +1 -1
  84. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/AzureDevOpsModelServiceGenerator.spec.d.ts +5 -0
  85. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/AzureDevOpsModelServiceGenerator.spec.d.ts.map +1 -0
  86. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/AzureDevOpsModelServiceGenerator.spec.js +93 -0
  87. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/AzureDevOpsModelServiceGenerator.spec.js.map +1 -0
  88. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/DataSourceInfoProcessor.spec.js +897 -2
  89. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/DataSourceInfoProcessor.spec.js.map +1 -1
  90. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/ModelServiceGenerator.spec.js +1 -17
  91. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/ModelServiceGenerator.spec.js.map +1 -1
  92. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/arrayTypeGeneration.spec.d.ts +5 -0
  93. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/arrayTypeGeneration.spec.d.ts.map +1 -0
  94. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/arrayTypeGeneration.spec.js +63 -0
  95. package/node_modules/@microsoft/powerapps-player-actions/lib/__tests__/arrayTypeGeneration.spec.js.map +1 -0
  96. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/Actions/PushApp.js +9 -4
  97. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/Actions/PushApp.js.map +1 -1
  98. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/codeGenUtils.d.ts +20 -0
  99. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/codeGenUtils.d.ts.map +1 -1
  100. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/codeGenUtils.js +86 -1
  101. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/codeGenUtils.js.map +1 -1
  102. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/dataSourceInfoProcessor.d.ts +2 -2
  103. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/dataSourceInfoProcessor.d.ts.map +1 -1
  104. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/dataSourceInfoProcessor.js +25 -67
  105. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/dataSourceInfoProcessor.js.map +1 -1
  106. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/modelServiceGenerator.d.ts +0 -59
  107. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/modelServiceGenerator.d.ts.map +1 -1
  108. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/modelServiceGenerator.js +65 -279
  109. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/modelServiceGenerator.js.map +1 -1
  110. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/nameUtility.d.ts +26 -0
  111. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/nameUtility.d.ts.map +1 -1
  112. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/nameUtility.js +161 -1
  113. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/CodeGen/nameUtility.js.map +1 -1
  114. package/node_modules/@microsoft/{powerapps-data/lib/components/codeGen/dataSourceInfo.js → powerapps-player-actions/lib-cjs/__tests__/AzureDevOpsModelServiceGenerator.spec.d.ts} +0 -1
  115. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/AzureDevOpsModelServiceGenerator.spec.d.ts.map +1 -0
  116. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/AzureDevOpsModelServiceGenerator.spec.js +206 -0
  117. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/AzureDevOpsModelServiceGenerator.spec.js.map +1 -0
  118. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/DataSourceInfoProcessor.spec.js +1277 -1
  119. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/DataSourceInfoProcessor.spec.js.map +1 -1
  120. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/ModelServiceGenerator.spec.js +0 -32
  121. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/ModelServiceGenerator.spec.js.map +1 -1
  122. package/node_modules/@microsoft/{powerapps-data/lib/__tests__/dataSourceInfoProcessor.test.d.ts → powerapps-player-actions/lib-cjs/__tests__/arrayTypeGeneration.spec.d.ts} +0 -1
  123. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/arrayTypeGeneration.spec.d.ts.map +1 -0
  124. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/arrayTypeGeneration.spec.js +171 -0
  125. package/node_modules/@microsoft/powerapps-player-actions/lib-cjs/__tests__/arrayTypeGeneration.spec.js.map +1 -0
  126. package/node_modules/@microsoft/powerapps-player-actions/package.json +2 -2
  127. package/node_modules/@pa-client/powerapps-player-services/package.json +1 -1
  128. package/package.json +4 -4
  129. package/node_modules/@microsoft/powerapps-data/lib/__tests__/dataSourceInfoProcessor.test.d.ts.map +0 -1
  130. package/node_modules/@microsoft/powerapps-data/lib/__tests__/dataSourceInfoProcessor.test.js +0 -782
  131. package/node_modules/@microsoft/powerapps-data/lib/__tests__/dataSourceInfoProcessor.test.js.map +0 -1
  132. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfo.d.ts +0 -28
  133. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfo.d.ts.map +0 -1
  134. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfo.js.map +0 -1
  135. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfoProcessor.d.ts +0 -10
  136. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfoProcessor.d.ts.map +0 -1
  137. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfoProcessor.js +0 -530
  138. package/node_modules/@microsoft/powerapps-data/lib/components/codeGen/dataSourceInfoProcessor.js.map +0 -1
@@ -3,13 +3,28 @@
3
3
  */
4
4
  import * as fs from 'fs';
5
5
  import * as path from 'path';
6
- import { afterEach, beforeEach, describe, it } from '@jest/globals';
6
+ import { afterEach, beforeEach, describe, it, jest } from '@jest/globals';
7
7
  import { clearVfs, setVfs } from '../VfsManager';
8
8
  import mockVfs from './mocks/mockVfs';
9
9
  import { extractDeclaration } from './Utils';
10
10
  import { processDataSourceInfo } from '../CodeGen/dataSourceInfoProcessor';
11
11
  import { beforeAll, expect } from '@jest/globals';
12
12
  import { getMockLogger } from './mocks/Logger.mock';
13
+ /**
14
+ * Parses the generated TypeScript content and returns the DataSourcesInfo object.
15
+ * This provides type-safe access to the generated data structure instead of fragile string checks.
16
+ * @param generatedContent The generated TypeScript file content
17
+ * @returns The parsed DataSourcesInfo object
18
+ */
19
+ function parseDataSourcesInfo(generatedContent) {
20
+ const jsonMatch = generatedContent.match(/export const dataSourcesInfo = ({[\s\S]*});?\s*$/);
21
+ if (!jsonMatch) {
22
+ throw new Error('Could not extract dataSourcesInfo from generated content');
23
+ }
24
+ // Remove trailing semicolon if present
25
+ const jsonStr = jsonMatch[1].replace(/;\s*$/, '');
26
+ return JSON.parse(jsonStr);
27
+ }
13
28
  async function setupMockSchemas() {
14
29
  // Reset the mock filesystem
15
30
  mockVfs.reset();
@@ -25,7 +40,7 @@ const localFilePaths = {
25
40
  codeGenPath: `${baseTestDir}\\src`,
26
41
  };
27
42
  const mockLogger = getMockLogger();
28
- describe('ModelServiceGenerator', () => {
43
+ describe('dataSourceInfoProcessor with real schema files', () => {
29
44
  beforeAll(async () => {
30
45
  await setupMockSchemas();
31
46
  });
@@ -51,4 +66,884 @@ describe('ModelServiceGenerator', () => {
51
66
  });
52
67
  });
53
68
  });
69
+ describe('dataSourceInfoProcessor with mocked schema files', () => {
70
+ beforeEach(() => {
71
+ jest.clearAllMocks();
72
+ mockVfs.reset();
73
+ setVfs(mockVfs);
74
+ });
75
+ afterEach(() => {
76
+ clearVfs();
77
+ });
78
+ describe('processDataSourceInfo', () => {
79
+ it('should process empty folder without errors', async () => {
80
+ // Arrange
81
+ const folderPath = '/test/folder';
82
+ await mockVfs.mkdir(folderPath, { recursive: true });
83
+ // Act & Assert
84
+ await expect(processDataSourceInfo(folderPath, mockLogger)).resolves.not.toThrow();
85
+ });
86
+ it('should process folder with JSON files and generate output', async () => {
87
+ // Arrange
88
+ const folderPath = '/test/folder';
89
+ const jsonContent = JSON.stringify({
90
+ name: 'test-api',
91
+ type: 'Microsoft.PowerApps/apis',
92
+ properties: {
93
+ swagger: {
94
+ paths: {
95
+ '/test': {
96
+ get: {
97
+ operationId: 'GetTest',
98
+ responses: {
99
+ '200': {
100
+ description: 'Success',
101
+ },
102
+ },
103
+ },
104
+ },
105
+ },
106
+ },
107
+ },
108
+ });
109
+ // Setup mock file system
110
+ await mockVfs.mkdir(folderPath, { recursive: true });
111
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'test.json'), jsonContent);
112
+ // Act
113
+ await processDataSourceInfo(folderPath, mockLogger);
114
+ // Assert
115
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
116
+ const outputExists = await mockVfs.exists(outputPath);
117
+ expect(outputExists).toBe(true);
118
+ });
119
+ it('should handle file processing errors with file path context', async () => {
120
+ // Arrange
121
+ const folderPath = '/test/folder';
122
+ const invalidJsonContent = '{ invalid json';
123
+ await mockVfs.mkdir(folderPath, { recursive: true });
124
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'invalid.json'), invalidJsonContent);
125
+ // Act & Assert
126
+ await expect(processDataSourceInfo(folderPath, mockLogger)).rejects.toThrow(/Error processing file.*invalid\.json/);
127
+ });
128
+ it('should create output directory if it does not exist', async () => {
129
+ // Arrange
130
+ const folderPath = '/test/folder';
131
+ await mockVfs.mkdir(folderPath, { recursive: true });
132
+ // Act
133
+ await processDataSourceInfo(folderPath, mockLogger);
134
+ // Assert
135
+ const outputDir = mockVfs.join(folderPath, 'appschemas');
136
+ const dirExists = await mockVfs.exists(outputDir);
137
+ expect(dirExists).toBe(true);
138
+ });
139
+ });
140
+ describe('Swagger API processing', () => {
141
+ it('should process Microsoft.PowerApps/apis type with swagger paths', async () => {
142
+ var _a, _b, _c, _d, _e, _f;
143
+ // Arrange
144
+ const folderPath = '/test/folder';
145
+ const swaggerJson = {
146
+ name: 'users-api',
147
+ type: 'Microsoft.PowerApps/apis',
148
+ properties: {
149
+ swagger: {
150
+ paths: {
151
+ '/users': {
152
+ get: {
153
+ operationId: 'GetUsers',
154
+ parameters: [
155
+ {
156
+ name: 'limit',
157
+ in: 'query',
158
+ required: false,
159
+ type: 'integer',
160
+ },
161
+ ],
162
+ responses: {
163
+ '200': {
164
+ description: 'Success',
165
+ schema: {
166
+ type: 'array',
167
+ },
168
+ },
169
+ },
170
+ },
171
+ post: {
172
+ operationId: 'CreateUser',
173
+ responses: {
174
+ '201': {
175
+ description: 'Created',
176
+ },
177
+ },
178
+ },
179
+ },
180
+ },
181
+ },
182
+ },
183
+ };
184
+ await mockVfs.mkdir(folderPath, { recursive: true });
185
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'swagger.json'), JSON.stringify(swaggerJson));
186
+ // Act
187
+ await processDataSourceInfo(folderPath, mockLogger);
188
+ // Assert
189
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
190
+ const generatedContent = await mockVfs.readFile(outputPath);
191
+ const parsed = parseDataSourcesInfo(generatedContent);
192
+ // Verify the data source exists with sanitized name (hyphens become underscores)
193
+ expect(parsed).toHaveProperty('users_api');
194
+ const dataSource = parsed.users_api;
195
+ // Verify APIs are generated correctly
196
+ expect(dataSource.apis).toHaveProperty('GetUsers');
197
+ expect(dataSource.apis).toHaveProperty('CreateUser');
198
+ // Verify GetUsers API details
199
+ const getUsersApi = dataSource.apis.GetUsers;
200
+ expect(getUsersApi.path).toBe('/users');
201
+ expect(getUsersApi.method).toBe('GET');
202
+ expect(getUsersApi.parameters).toBeDefined();
203
+ expect((_a = getUsersApi.parameters) === null || _a === void 0 ? void 0 : _a.length).toBe(1);
204
+ expect((_b = getUsersApi.parameters) === null || _b === void 0 ? void 0 : _b[0].name).toBe('limit');
205
+ expect((_d = (_c = getUsersApi.responseInfo) === null || _c === void 0 ? void 0 : _c['200']) === null || _d === void 0 ? void 0 : _d.type).toBe('array');
206
+ // Verify CreateUser API details
207
+ const createUserApi = dataSource.apis.CreateUser;
208
+ expect(createUserApi.path).toBe('/users');
209
+ expect(createUserApi.method).toBe('POST');
210
+ expect((_f = (_e = createUserApi.responseInfo) === null || _e === void 0 ? void 0 : _e['201']) === null || _f === void 0 ? void 0 : _f.type).toBe('void');
211
+ });
212
+ it('should handle swagger with parameter references', async () => {
213
+ // Arrange
214
+ const folderPath = '/test/folder';
215
+ const swaggerJson = {
216
+ name: 'items-api',
217
+ type: 'Microsoft.PowerApps/apis',
218
+ properties: {
219
+ swagger: {
220
+ paths: {
221
+ '/items': {
222
+ get: {
223
+ operationId: 'GetItems',
224
+ parameters: [
225
+ {
226
+ $ref: '#/swagger/parameters/CommonParam',
227
+ },
228
+ ],
229
+ responses: {
230
+ '200': {
231
+ description: 'Success',
232
+ },
233
+ },
234
+ },
235
+ },
236
+ },
237
+ parameters: {
238
+ CommonParam: {
239
+ name: 'commonParam',
240
+ in: 'header',
241
+ required: true,
242
+ type: 'string',
243
+ },
244
+ },
245
+ },
246
+ },
247
+ };
248
+ await mockVfs.mkdir(folderPath, { recursive: true });
249
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'swagger-ref.json'), JSON.stringify(swaggerJson));
250
+ // Act
251
+ await processDataSourceInfo(folderPath, mockLogger);
252
+ // Assert
253
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
254
+ const generatedContent = await mockVfs.readFile(outputPath);
255
+ expect(generatedContent).toContain('items_api');
256
+ expect(generatedContent).toContain('GetItems');
257
+ // Note: Parameter reference resolution is tested but the mock doesn't properly resolve it
258
+ // The actual implementation would resolve the commonParam parameter
259
+ });
260
+ it('should handle responses with schema references', async () => {
261
+ // Arrange
262
+ const folderPath = '/test/folder';
263
+ const swaggerJson = {
264
+ name: 'models-api',
265
+ type: 'Microsoft.PowerApps/apis',
266
+ properties: {
267
+ swagger: {
268
+ paths: {
269
+ '/models': {
270
+ get: {
271
+ operationId: 'GetModels',
272
+ responses: {
273
+ '200': {
274
+ description: 'Success',
275
+ schema: {
276
+ $ref: '#/definitions/ModelResponse',
277
+ },
278
+ },
279
+ },
280
+ },
281
+ },
282
+ },
283
+ definitions: {
284
+ ModelResponse: {
285
+ type: 'object',
286
+ },
287
+ },
288
+ },
289
+ },
290
+ };
291
+ await mockVfs.mkdir(folderPath, { recursive: true });
292
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'models.json'), JSON.stringify(swaggerJson));
293
+ // Act
294
+ await processDataSourceInfo(folderPath, mockLogger);
295
+ // Assert
296
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
297
+ const generatedContent = await mockVfs.readFile(outputPath);
298
+ expect(generatedContent).toContain('GetModels');
299
+ expect(generatedContent).toContain('"type": "object"');
300
+ });
301
+ });
302
+ describe('SQL stored procedure processing', () => {
303
+ it('should process SQL stored procedure with input parameters', async () => {
304
+ var _a, _b;
305
+ // Arrange
306
+ const folderPath = '/test/procedures/GetUserById';
307
+ const procedureJson = {
308
+ name: '[dbo].[GetUserById]',
309
+ schema: {
310
+ procedureresultschema: {
311
+ type: 'object',
312
+ },
313
+ inputparameters: {
314
+ properties: {
315
+ UserId: {
316
+ type: 'integer',
317
+ required: true,
318
+ },
319
+ IncludeDetails: {
320
+ type: 'boolean',
321
+ required: false,
322
+ },
323
+ },
324
+ },
325
+ },
326
+ };
327
+ await mockVfs.mkdir(folderPath, { recursive: true });
328
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'procedure.json'), JSON.stringify(procedureJson));
329
+ // Act
330
+ await processDataSourceInfo(folderPath, mockLogger);
331
+ // Assert
332
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
333
+ const generatedContent = await mockVfs.readFile(outputPath);
334
+ const parsed = parseDataSourcesInfo(generatedContent);
335
+ // Verify the data source exists (uses parent folder name as key)
336
+ expect(parsed).toHaveProperty('getuserbyid');
337
+ const dataSource = parsed.getuserbyid;
338
+ // Verify the stored procedure API
339
+ expect(dataSource.apis).toHaveProperty('GetUserById');
340
+ const procApi = dataSource.apis.GetUserById;
341
+ expect(procApi.path).toBe('/dbo.GetUserById');
342
+ expect(procApi.method).toBe('POST');
343
+ // Verify parameters are present
344
+ expect(procApi.parameters).toBeDefined();
345
+ const paramNames = (_b = (_a = procApi.parameters) === null || _a === void 0 ? void 0 : _a.map((p) => p.name)) !== null && _b !== void 0 ? _b : [];
346
+ expect(paramNames).toContain('UserId');
347
+ expect(paramNames).toContain('IncludeDetails');
348
+ });
349
+ it('should handle stored procedure without input parameters', async () => {
350
+ // Arrange
351
+ const folderPath = '/test/procedures/GetAllUsers';
352
+ const procedureJson = {
353
+ name: '[dbo].[GetAllUsers]',
354
+ schema: {
355
+ procedureresultschema: {
356
+ type: 'array',
357
+ },
358
+ },
359
+ };
360
+ await mockVfs.mkdir(folderPath, { recursive: true });
361
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'procedure.json'), JSON.stringify(procedureJson));
362
+ // Act
363
+ await processDataSourceInfo(folderPath, mockLogger);
364
+ // Assert
365
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
366
+ const generatedContent = await mockVfs.readFile(outputPath);
367
+ expect(generatedContent).toContain('getallusers');
368
+ expect(generatedContent).toContain('"/dbo.GetAllUsers"');
369
+ });
370
+ it('should determine property key from parent folder for stored procedures', async () => {
371
+ // Arrange
372
+ const folderPath = '/test/procedures/UserProcedures';
373
+ const procedureJson = {
374
+ name: '[dbo].[GetUser]',
375
+ schema: {
376
+ procedureresultschema: {
377
+ type: 'object',
378
+ },
379
+ },
380
+ };
381
+ await mockVfs.mkdir(folderPath, { recursive: true });
382
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'procedure.json'), JSON.stringify(procedureJson));
383
+ // Act
384
+ await processDataSourceInfo(folderPath, mockLogger);
385
+ // Assert
386
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
387
+ const generatedContent = await mockVfs.readFile(outputPath);
388
+ expect(generatedContent).toContain('userprocedures');
389
+ });
390
+ it('should handle non-dbo schemas', async () => {
391
+ // Arrange
392
+ const folderPath = '/test/procedures/GetAllUsers';
393
+ const procedureJson = {
394
+ name: '[foo].[GetAllUsers]',
395
+ schema: {
396
+ procedureresultschema: {
397
+ type: 'array',
398
+ },
399
+ },
400
+ };
401
+ await mockVfs.mkdir(folderPath, { recursive: true });
402
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'procedure.json'), JSON.stringify(procedureJson));
403
+ // Act
404
+ await processDataSourceInfo(folderPath, mockLogger);
405
+ // Assert
406
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
407
+ const generatedContent = await mockVfs.readFile(outputPath);
408
+ expect(generatedContent).toContain('getallusers');
409
+ expect(generatedContent).toContain('"/foo.GetAllUsers"');
410
+ });
411
+ });
412
+ describe('SQL table processing', () => {
413
+ it('should process SQL table schema with primary key', async () => {
414
+ // Arrange
415
+ const folderPath = '/test/tables';
416
+ const tableJson = {
417
+ name: '[dbo].[Users]',
418
+ schema: {
419
+ items: {
420
+ properties: {
421
+ Id: {
422
+ type: 'integer',
423
+ 'x-ms-keyType': 'primary',
424
+ },
425
+ Name: {
426
+ type: 'string',
427
+ },
428
+ Email: {
429
+ type: 'string',
430
+ },
431
+ },
432
+ },
433
+ },
434
+ };
435
+ await mockVfs.mkdir(folderPath, { recursive: true });
436
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'users.json'), JSON.stringify(tableJson));
437
+ // Act
438
+ await processDataSourceInfo(folderPath, mockLogger);
439
+ // Assert
440
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
441
+ const generatedContent = await mockVfs.readFile(outputPath);
442
+ const parsed = parseDataSourcesInfo(generatedContent);
443
+ // Note: when schema path doesn't contain /sql/, sanitizeName is used which converts [dbo].[Users] to _dbo___users_ (lowercase)
444
+ const expectedKey = '_dbo___users_';
445
+ expect(parsed).toHaveProperty(expectedKey);
446
+ const dataSource = parsed[expectedKey];
447
+ // Verify SQL table properties - tableId gets the cleaned name from sanitizeSqlName
448
+ expect(dataSource.tableId).toBe('Users');
449
+ expect(dataSource.version).toBe('v2');
450
+ expect(dataSource.primaryKey).toBe('Id');
451
+ expect(dataSource.dataSourceType).toBe('Connector');
452
+ });
453
+ it('should handle table without primary key', async () => {
454
+ // Arrange
455
+ const folderPath = '/test/sql/tables';
456
+ const tableJson = {
457
+ name: '[dbo].[Logs]',
458
+ schema: {
459
+ items: {
460
+ properties: {
461
+ Message: {
462
+ type: 'string',
463
+ },
464
+ Timestamp: {
465
+ type: 'string',
466
+ },
467
+ },
468
+ },
469
+ },
470
+ };
471
+ await mockVfs.mkdir(folderPath, { recursive: true });
472
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'logs.json'), JSON.stringify(tableJson));
473
+ // Act
474
+ await processDataSourceInfo(folderPath, mockLogger);
475
+ // Assert
476
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
477
+ const generatedContent = await mockVfs.readFile(outputPath);
478
+ const parsed = parseDataSourcesInfo(generatedContent);
479
+ // When schema path contains /sql/, sanitizeSqlName extracts just "Logs" from [dbo].[Logs], then lowercase
480
+ const expectedKey = 'logs';
481
+ expect(parsed).toHaveProperty(expectedKey);
482
+ const dataSource = parsed[expectedKey];
483
+ // Verify primary key is empty when not specified
484
+ expect(dataSource.tableId).toBe('Logs');
485
+ expect(dataSource.primaryKey).toBe('');
486
+ });
487
+ });
488
+ describe('Property key determination', () => {
489
+ it('should remove [dbo]. prefix and brackets from SQL table names', async () => {
490
+ // Arrange
491
+ const folderPath = '/test/tables';
492
+ const tableJson = {
493
+ name: '[dbo].[ComplexTableName]',
494
+ schema: {
495
+ items: {
496
+ properties: {},
497
+ },
498
+ },
499
+ };
500
+ await mockVfs.mkdir(folderPath, { recursive: true });
501
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'table.json'), JSON.stringify(tableJson));
502
+ // Act
503
+ await processDataSourceInfo(folderPath, mockLogger);
504
+ // Assert
505
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
506
+ const generatedContent = await mockVfs.readFile(outputPath);
507
+ expect(generatedContent).toContain('ComplexTableName');
508
+ });
509
+ it('should remove [custom_schema]. prefix and brackets from SQL table names', async () => {
510
+ // Arrange
511
+ const folderPath = '/test/tables';
512
+ const tableJson = {
513
+ name: '[custom_schema].[ComplexTableName]',
514
+ schema: {
515
+ items: {
516
+ properties: {},
517
+ },
518
+ },
519
+ };
520
+ await mockVfs.mkdir(folderPath, { recursive: true });
521
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'table.json'), JSON.stringify(tableJson));
522
+ // Act
523
+ await processDataSourceInfo(folderPath, mockLogger);
524
+ // Assert
525
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
526
+ const generatedContent = await mockVfs.readFile(outputPath);
527
+ expect(generatedContent).toContain('ComplexTableName');
528
+ });
529
+ it('should remove shared_ prefix from non-tabular names', async () => {
530
+ // Arrange
531
+ const folderPath = '/test/shared';
532
+ const sharedJson = {
533
+ name: 'shared_commonservice',
534
+ properties: {
535
+ displayName: 'CommonService',
536
+ },
537
+ schema: {
538
+ type: 'object',
539
+ },
540
+ };
541
+ await mockVfs.mkdir(folderPath, { recursive: true });
542
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'service.json'), JSON.stringify(sharedJson));
543
+ // Act
544
+ await processDataSourceInfo(folderPath, mockLogger);
545
+ // Assert
546
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
547
+ const generatedContent = await mockVfs.readFile(outputPath);
548
+ expect(generatedContent).toContain('commonservice');
549
+ });
550
+ it('should use title property when available', async () => {
551
+ // Arrange
552
+ const folderPath = '/test/tabular';
553
+ const tabularJson = {
554
+ title: 'UserManagement',
555
+ name: 'internal_name',
556
+ schema: {
557
+ type: 'object',
558
+ },
559
+ };
560
+ await mockVfs.mkdir(folderPath, { recursive: true });
561
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'service.json'), JSON.stringify(tabularJson));
562
+ // Act
563
+ await processDataSourceInfo(folderPath, mockLogger);
564
+ // Assert
565
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
566
+ const generatedContent = await mockVfs.readFile(outputPath);
567
+ expect(generatedContent).toContain('internal_name');
568
+ });
569
+ it('should fallback to filename when name property is missing', async () => {
570
+ // Arrange
571
+ const folderPath = '/test/fallback';
572
+ const jsonWithoutName = {
573
+ schema: {
574
+ type: 'object',
575
+ },
576
+ };
577
+ await mockVfs.mkdir(folderPath, { recursive: true });
578
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'FallbackService.Schema.json'), JSON.stringify(jsonWithoutName));
579
+ // Act
580
+ await processDataSourceInfo(folderPath, mockLogger);
581
+ // Assert
582
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
583
+ const generatedContent = await mockVfs.readFile(outputPath);
584
+ const parsed = parseDataSourcesInfo(generatedContent);
585
+ // When name property is missing, fallback to filename (minus .json extension, lowercased)
586
+ const expectedKey = 'fallbackservice.schema';
587
+ expect(parsed).toHaveProperty([expectedKey]);
588
+ });
589
+ it('should handle names with spaces and underscores', async () => {
590
+ // Arrange
591
+ const folderPath = '/test/complexnames';
592
+ const complexNameJson = {
593
+ name: ' Complex_Name With Spaces ',
594
+ title: ' Complex_Name With Spaces ',
595
+ schema: {
596
+ type: 'object',
597
+ },
598
+ };
599
+ await mockVfs.mkdir(folderPath, { recursive: true });
600
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'complex.json'), JSON.stringify(complexNameJson));
601
+ // Act
602
+ await processDataSourceInfo(folderPath, mockLogger);
603
+ // Assert
604
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
605
+ const generatedContent = await mockVfs.readFile(outputPath);
606
+ // Keys are now lowercase
607
+ expect(generatedContent).toContain('complex_namewithspaces');
608
+ });
609
+ it('should use name property for SharePoint list with underscores and hyphens', async () => {
610
+ // Arrange
611
+ const folderPath = '/test/sharepointspecialname';
612
+ const sharepointListJson = {
613
+ name: 'PaKeMpar_list with underscores-and hype-ns',
614
+ title: 'PaKeMpar_list with underscores-and hype-ns',
615
+ 'x-ms-permission': 'read-write',
616
+ 'x-ms-capabilities': {
617
+ sortRestrictions: {
618
+ sortable: true,
619
+ unsortableProperties: [],
620
+ },
621
+ },
622
+ schema: {
623
+ type: 'array',
624
+ items: {
625
+ type: 'object',
626
+ properties: {
627
+ ID: {
628
+ title: 'ID',
629
+ type: 'integer',
630
+ 'x-ms-keyType': 'primary',
631
+ },
632
+ Title: {
633
+ title: 'Title',
634
+ type: 'string',
635
+ },
636
+ },
637
+ },
638
+ },
639
+ referencedEntities: {
640
+ Author: {
641
+ lookupEndpoint: {
642
+ path: '/tables/e34fc1b5-7e29-473a-9863-553afa820351/entities/Author',
643
+ },
644
+ },
645
+ Editor: {
646
+ lookupEndpoint: {
647
+ path: '/tables/e34fc1b5-7e29-473a-9863-553afa820351/entities/Editor',
648
+ },
649
+ },
650
+ },
651
+ };
652
+ await mockVfs.mkdir(folderPath, { recursive: true });
653
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'speciallist.json'), JSON.stringify(sharepointListJson));
654
+ // Act
655
+ await processDataSourceInfo(folderPath, mockLogger);
656
+ // Assert
657
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
658
+ const generatedContent = await mockVfs.readFile(outputPath);
659
+ const parsed = parseDataSourcesInfo(generatedContent);
660
+ // The property key should be sanitized: spaces removed, hyphens converted to underscores
661
+ const expectedKey = 'pakempar_listwithunderscores_andhype_ns';
662
+ expect(parsed).toHaveProperty(expectedKey);
663
+ const dataSource = parsed[expectedKey];
664
+ // tableId should preserve the original name from the schema
665
+ expect(dataSource.tableId).toBe('PaKeMpar_list with underscores-and hype-ns');
666
+ expect(dataSource.primaryKey).toBe('ID');
667
+ expect(dataSource.dataSourceType).toBe('Connector');
668
+ // Should have APIs generated from referencedEntities
669
+ expect(dataSource.apis).toHaveProperty('GetAuthor');
670
+ expect(dataSource.apis).toHaveProperty('GetEditor');
671
+ // Verify API paths have GUIDs without hyphens
672
+ expect(dataSource.apis.GetAuthor.path).toContain('e34fc1b57e29473a9863553afa820351');
673
+ });
674
+ });
675
+ describe('Merge functionality', () => {
676
+ it('should merge APIs when processing multiple files for same data source', async () => {
677
+ // Arrange
678
+ const folderPath = '/test/merge';
679
+ const api1Json = {
680
+ name: 'shared_testservice',
681
+ type: 'Microsoft.PowerApps/apis',
682
+ properties: {
683
+ displayName: 'TestService',
684
+ swagger: {
685
+ paths: {
686
+ '/api1': {
687
+ get: {
688
+ operationId: 'GetApi1',
689
+ responses: { '200': { description: 'Success' } },
690
+ },
691
+ },
692
+ },
693
+ },
694
+ },
695
+ };
696
+ const api2Json = {
697
+ name: 'shared_testservice',
698
+ type: 'Microsoft.PowerApps/apis',
699
+ properties: {
700
+ displayName: 'TestService',
701
+ swagger: {
702
+ paths: {
703
+ '/api2': {
704
+ post: {
705
+ operationId: 'PostApi2',
706
+ responses: { '201': { description: 'Created' } },
707
+ },
708
+ },
709
+ },
710
+ },
711
+ },
712
+ };
713
+ await mockVfs.mkdir(folderPath, { recursive: true });
714
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'api1.json'), JSON.stringify(api1Json));
715
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'api2.json'), JSON.stringify(api2Json));
716
+ // Act
717
+ await processDataSourceInfo(folderPath, mockLogger);
718
+ // Assert
719
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
720
+ const generatedContent = await mockVfs.readFile(outputPath);
721
+ expect(generatedContent).toContain('GetApi1');
722
+ expect(generatedContent).toContain('PostApi2');
723
+ expect(generatedContent).toContain('testservice');
724
+ });
725
+ it('should handle duplicate stored procedures gracefully', async () => {
726
+ // Arrange
727
+ const folderPath = '/test/duplicate';
728
+ const procedureJson = {
729
+ name: '[dbo].[DuplicateProc]',
730
+ schema: {
731
+ procedureresultschema: { type: 'object' },
732
+ },
733
+ };
734
+ await mockVfs.mkdir(folderPath, { recursive: true });
735
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'proc1.json'), JSON.stringify(procedureJson));
736
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'proc2.json'), JSON.stringify(procedureJson));
737
+ // Act & Assert
738
+ // Note: The current implementation merges APIs instead of throwing an error
739
+ // This test verifies that duplicate stored procedures are handled gracefully
740
+ await expect(processDataSourceInfo(folderPath, mockLogger)).resolves.not.toThrow();
741
+ });
742
+ });
743
+ describe('Response processing', () => {
744
+ it('should handle array responses correctly', async () => {
745
+ var _a, _b, _c, _d;
746
+ // Arrange
747
+ const folderPath = '/test/responses';
748
+ const swaggerJson = {
749
+ name: 'array-api',
750
+ type: 'Microsoft.PowerApps/apis',
751
+ properties: {
752
+ swagger: {
753
+ paths: {
754
+ '/array-endpoint': {
755
+ get: {
756
+ operationId: 'GetArray',
757
+ responses: {
758
+ '200': {
759
+ description: 'Success',
760
+ schema: {
761
+ type: 'array',
762
+ format: 'custom',
763
+ },
764
+ },
765
+ },
766
+ },
767
+ },
768
+ },
769
+ },
770
+ },
771
+ };
772
+ await mockVfs.mkdir(folderPath, { recursive: true });
773
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'array-response.json'), JSON.stringify(swaggerJson));
774
+ // Act
775
+ await processDataSourceInfo(folderPath, mockLogger);
776
+ // Assert
777
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
778
+ const generatedContent = await mockVfs.readFile(outputPath);
779
+ const parsed = parseDataSourcesInfo(generatedContent);
780
+ // Verify the data source exists with sanitized name
781
+ expect(parsed).toHaveProperty('array_api');
782
+ const dataSource = parsed.array_api;
783
+ // Verify response info for GetArray
784
+ const getArrayApi = dataSource.apis.GetArray;
785
+ expect((_b = (_a = getArrayApi.responseInfo) === null || _a === void 0 ? void 0 : _a['200']) === null || _b === void 0 ? void 0 : _b.type).toBe('array');
786
+ expect((_d = (_c = getArrayApi.responseInfo) === null || _c === void 0 ? void 0 : _c['200']) === null || _d === void 0 ? void 0 : _d.format).toBe('custom');
787
+ });
788
+ it('should handle void responses when no schema provided', async () => {
789
+ var _a, _b;
790
+ // Arrange
791
+ const folderPath = '/test/responses';
792
+ const swaggerJson = {
793
+ name: 'void-api',
794
+ type: 'Microsoft.PowerApps/apis',
795
+ properties: {
796
+ swagger: {
797
+ paths: {
798
+ '/void-endpoint': {
799
+ delete: {
800
+ operationId: 'DeleteItem',
801
+ responses: {
802
+ '204': {
803
+ description: 'No Content',
804
+ },
805
+ },
806
+ },
807
+ },
808
+ },
809
+ },
810
+ },
811
+ };
812
+ await mockVfs.mkdir(folderPath, { recursive: true });
813
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'void-response.json'), JSON.stringify(swaggerJson));
814
+ // Act
815
+ await processDataSourceInfo(folderPath, mockLogger);
816
+ // Assert
817
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
818
+ const generatedContent = await mockVfs.readFile(outputPath);
819
+ const parsed = parseDataSourcesInfo(generatedContent);
820
+ // Verify the data source exists with sanitized name
821
+ expect(parsed).toHaveProperty('void_api');
822
+ const dataSource = parsed.void_api;
823
+ // Verify response info for DeleteItem is void when no schema provided
824
+ const deleteApi = dataSource.apis.DeleteItem;
825
+ expect((_b = (_a = deleteApi.responseInfo) === null || _a === void 0 ? void 0 : _a['204']) === null || _b === void 0 ? void 0 : _b.type).toBe('void');
826
+ });
827
+ });
828
+ describe('Error handling', () => {
829
+ it('should throw descriptive error for invalid JSON structure', async () => {
830
+ // Arrange
831
+ const folderPath = '/test/invalid';
832
+ const invalidJson = {
833
+ invalidStructure: true,
834
+ };
835
+ await mockVfs.mkdir(folderPath, { recursive: true });
836
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'invalid.json'), JSON.stringify(invalidJson));
837
+ // Act & Assert
838
+ await expect(processDataSourceInfo(folderPath, mockLogger)).rejects.toThrow('The JSON does not represent a valid data source');
839
+ });
840
+ it('should handle nested directory traversal', async () => {
841
+ // Arrange
842
+ const folderPath = '/test/nested';
843
+ const subfolderPath = mockVfs.join(folderPath, 'subfolder');
844
+ const nestedJson = {
845
+ name: 'nested-service',
846
+ schema: { type: 'object' },
847
+ };
848
+ await mockVfs.mkdir(subfolderPath, { recursive: true });
849
+ await mockVfs.writeFile(mockVfs.join(subfolderPath, 'nested.json'), JSON.stringify(nestedJson));
850
+ // Act
851
+ await processDataSourceInfo(folderPath, mockLogger);
852
+ // Assert - verify output was generated (means nested traversal worked)
853
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
854
+ const outputExists = await mockVfs.exists(outputPath);
855
+ expect(outputExists).toBe(true);
856
+ });
857
+ });
858
+ describe('Parameter sorting', () => {
859
+ it('should sort parameters with required first', async () => {
860
+ // Arrange
861
+ const folderPath = '/test/sorting';
862
+ const swaggerJson = {
863
+ name: 'sorting-api',
864
+ type: 'Microsoft.PowerApps/apis',
865
+ properties: {
866
+ swagger: {
867
+ paths: {
868
+ '/sorted-params': {
869
+ post: {
870
+ operationId: 'PostWithSortedParams',
871
+ parameters: [
872
+ {
873
+ name: 'optional1',
874
+ in: 'query',
875
+ required: false,
876
+ type: 'string',
877
+ },
878
+ {
879
+ name: 'required1',
880
+ in: 'body',
881
+ required: true,
882
+ type: 'object',
883
+ },
884
+ {
885
+ name: 'optional2',
886
+ in: 'header',
887
+ required: false,
888
+ type: 'string',
889
+ },
890
+ {
891
+ name: 'required2',
892
+ in: 'path',
893
+ required: true,
894
+ type: 'string',
895
+ },
896
+ ],
897
+ responses: {
898
+ '200': { description: 'Success' },
899
+ },
900
+ },
901
+ },
902
+ },
903
+ },
904
+ },
905
+ };
906
+ await mockVfs.mkdir(folderPath, { recursive: true });
907
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'sorted.json'), JSON.stringify(swaggerJson));
908
+ // Act
909
+ await processDataSourceInfo(folderPath, mockLogger);
910
+ // Assert
911
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
912
+ const generatedContent = await mockVfs.readFile(outputPath);
913
+ const parsed = parseDataSourcesInfo(generatedContent);
914
+ // Verify data source exists with sanitized name
915
+ expect(parsed).toHaveProperty('sorting_api');
916
+ const dataSource = parsed.sorting_api;
917
+ const operation = dataSource.apis.PostWithSortedParams;
918
+ const parameters = operation.parameters;
919
+ // Required parameters should come first
920
+ expect(parameters === null || parameters === void 0 ? void 0 : parameters[0].required).toBe(true);
921
+ expect(parameters === null || parameters === void 0 ? void 0 : parameters[1].required).toBe(true);
922
+ expect(parameters === null || parameters === void 0 ? void 0 : parameters[2].required).toBe(false);
923
+ expect(parameters === null || parameters === void 0 ? void 0 : parameters[3].required).toBe(false);
924
+ });
925
+ });
926
+ describe('Output generation', () => {
927
+ it('should generate properly formatted TypeScript output', async () => {
928
+ // Arrange
929
+ const folderPath = '/test/output';
930
+ const simpleJson = {
931
+ name: 'test-service',
932
+ schema: { type: 'object' },
933
+ };
934
+ await mockVfs.mkdir(folderPath, { recursive: true });
935
+ await mockVfs.writeFile(mockVfs.join(folderPath, 'simple.json'), JSON.stringify(simpleJson));
936
+ // Act
937
+ await processDataSourceInfo(folderPath, mockLogger);
938
+ // Assert
939
+ const outputPath = mockVfs.join(folderPath, 'appschemas', 'dataSourcesInfo.ts');
940
+ const content = await mockVfs.readFile(outputPath);
941
+ expect(content).toContain('/*!');
942
+ expect(content).toContain(' * Copyright (C) Microsoft Corporation. All rights reserved.');
943
+ expect(content).toContain(' * This file is auto-generated. Do not modify it manually.');
944
+ expect(content).toContain('export const dataSourcesInfo = ');
945
+ expect(content).toMatch(/;\s*$/); // Should end with semicolon
946
+ });
947
+ });
948
+ });
54
949
  //# sourceMappingURL=DataSourceInfoProcessor.spec.js.map