@teleporthq/teleport-plugin-next-data-source 0.42.4 → 0.42.6

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 (35) hide show
  1. package/dist/cjs/array-mapper-pagination.d.ts +5 -0
  2. package/dist/cjs/array-mapper-pagination.d.ts.map +1 -1
  3. package/dist/cjs/array-mapper-pagination.js.map +1 -1
  4. package/dist/cjs/array-mapper-registry.d.ts +84 -0
  5. package/dist/cjs/array-mapper-registry.d.ts.map +1 -0
  6. package/dist/cjs/array-mapper-registry.js +291 -0
  7. package/dist/cjs/array-mapper-registry.js.map +1 -0
  8. package/dist/cjs/index.d.ts.map +1 -1
  9. package/dist/cjs/index.js +36 -14
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/pagination-plugin.d.ts +1 -3
  12. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  13. package/dist/cjs/pagination-plugin.js +908 -1351
  14. package/dist/cjs/pagination-plugin.js.map +1 -1
  15. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  16. package/dist/esm/array-mapper-pagination.d.ts +5 -0
  17. package/dist/esm/array-mapper-pagination.d.ts.map +1 -1
  18. package/dist/esm/array-mapper-pagination.js.map +1 -1
  19. package/dist/esm/array-mapper-registry.d.ts +84 -0
  20. package/dist/esm/array-mapper-registry.d.ts.map +1 -0
  21. package/dist/esm/array-mapper-registry.js +287 -0
  22. package/dist/esm/array-mapper-registry.js.map +1 -0
  23. package/dist/esm/index.d.ts.map +1 -1
  24. package/dist/esm/index.js +36 -14
  25. package/dist/esm/index.js.map +1 -1
  26. package/dist/esm/pagination-plugin.d.ts +1 -3
  27. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  28. package/dist/esm/pagination-plugin.js +909 -1352
  29. package/dist/esm/pagination-plugin.js.map +1 -1
  30. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +2 -2
  32. package/src/array-mapper-pagination.ts +5 -0
  33. package/src/array-mapper-registry.ts +408 -0
  34. package/src/index.ts +24 -1
  35. package/src/pagination-plugin.ts +1860 -2132
@@ -34,24 +34,165 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
34
34
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
35
  }
36
36
  };
37
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
38
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
39
- if (ar || !(i in from)) {
40
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
41
- ar[i] = from[i];
42
- }
43
- }
44
- return to.concat(ar || Array.prototype.slice.call(from));
45
- };
46
37
  import { ChunkType, FileType, } from '@teleporthq/teleport-types';
47
38
  import * as types from '@babel/types';
48
- import { generatePaginationLogic } from './array-mapper-pagination';
49
- import { extractDataSourceIntoNextAPIFolder } from './utils';
39
+ import { StringUtils } from '@teleporthq/teleport-shared';
40
+ import { generateSafeFileName } from './utils';
41
+ // Scan UIDL to find all data source usages and build a registry
42
+ function buildStateRegistry(uidlNode) {
43
+ var usages = [];
44
+ var byDataSourceId = new Map();
45
+ var byArrayMapperRenderProp = new Map();
46
+ var index = 0;
47
+ var traverse = function (node, parentDataSource) {
48
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
49
+ if (!node || typeof node !== 'object') {
50
+ return;
51
+ }
52
+ // Found a data-source-list (DataProvider)
53
+ if (node.type === 'data-source-list' && ((_a = node.content) === null || _a === void 0 ? void 0 : _a.renderPropIdentifier)) {
54
+ var dsIdentifier = node.content.renderPropIdentifier;
55
+ var resourceDef = node.content.resourceDefinition || {};
56
+ var resourceParams = ((_b = node.content.resource) === null || _b === void 0 ? void 0 : _b.params) || {};
57
+ // Look for cms-list-repeater inside this data-source-list
58
+ var newParent = {
59
+ identifier: dsIdentifier,
60
+ resourceDef: resourceDef,
61
+ resourceParams: resourceParams,
62
+ };
63
+ // Traverse into success/error/loading nodes
64
+ if ((_c = node.content.nodes) === null || _c === void 0 ? void 0 : _c.success) {
65
+ traverse(node.content.nodes.success, newParent);
66
+ }
67
+ if ((_d = node.content.nodes) === null || _d === void 0 ? void 0 : _d.error) {
68
+ traverse(node.content.nodes.error, newParent);
69
+ }
70
+ if ((_e = node.content.nodes) === null || _e === void 0 ? void 0 : _e.loading) {
71
+ traverse(node.content.nodes.loading, newParent);
72
+ }
73
+ return;
74
+ }
75
+ // Found a cms-list-repeater (Repeater with pagination/search config)
76
+ var isCmsListRepeater = node.type === 'cms-list-repeater' ||
77
+ (node.type === 'element' && ((_f = node.content) === null || _f === void 0 ? void 0 : _f.elementType) === 'cms-list-repeater');
78
+ if (isCmsListRepeater && parentDataSource) {
79
+ var content = node.content || node;
80
+ var arrayMapperRenderProp = content.renderPropIdentifier;
81
+ if (arrayMapperRenderProp) {
82
+ // Extract query columns from parent's resource params
83
+ var queryColumns = [];
84
+ if ((_h = (_g = parentDataSource.resourceParams) === null || _g === void 0 ? void 0 : _g.queryColumns) === null || _h === void 0 ? void 0 : _h.content) {
85
+ queryColumns = parentDataSource.resourceParams.queryColumns.content;
86
+ }
87
+ // Extract limit from parent's resource params (for plain array mappers)
88
+ var limit = 0;
89
+ if ((_k = (_j = parentDataSource.resourceParams) === null || _j === void 0 ? void 0 : _j.limit) === null || _k === void 0 ? void 0 : _k.content) {
90
+ limit = parentDataSource.resourceParams.limit.content;
91
+ }
92
+ // For paginated mappers, use perPage from cms-list-repeater
93
+ // For plain mappers, use limit from data-source-list resource params
94
+ var effectivePerPage = content.paginated ? content.perPage : limit || content.perPage;
95
+ var usage = {
96
+ index: index++,
97
+ dataSourceIdentifier: parentDataSource.identifier,
98
+ arrayMapperRenderProp: arrayMapperRenderProp,
99
+ resourceDefinition: {
100
+ dataSourceId: parentDataSource.resourceDef.dataSourceId || '',
101
+ tableName: parentDataSource.resourceDef.tableName || '',
102
+ dataSourceType: parentDataSource.resourceDef.dataSourceType || '',
103
+ },
104
+ paginated: !!content.paginated,
105
+ perPage: effectivePerPage,
106
+ searchEnabled: !!content.searchEnabled,
107
+ searchDebounce: content.searchDebounce || 300,
108
+ queryColumns: queryColumns,
109
+ category: 'plain',
110
+ };
111
+ // Determine category
112
+ if (usage.paginated && usage.searchEnabled) {
113
+ usage.category = 'paginated+search';
114
+ }
115
+ else if (usage.paginated) {
116
+ usage.category = 'paginated-only';
117
+ }
118
+ else if (usage.searchEnabled) {
119
+ usage.category = 'search-only';
120
+ }
121
+ usages.push(usage);
122
+ // Add to maps
123
+ if (!byDataSourceId.has(usage.dataSourceIdentifier)) {
124
+ byDataSourceId.set(usage.dataSourceIdentifier, []);
125
+ }
126
+ byDataSourceId.get(usage.dataSourceIdentifier).push(usage);
127
+ byArrayMapperRenderProp.set(arrayMapperRenderProp, usage);
128
+ }
129
+ // Continue traversing inside the repeater
130
+ if ((_l = content.nodes) === null || _l === void 0 ? void 0 : _l.list) {
131
+ traverse(content.nodes.list, parentDataSource);
132
+ }
133
+ return;
134
+ }
135
+ // Recurse into children
136
+ if (((_m = node.content) === null || _m === void 0 ? void 0 : _m.children) && Array.isArray(node.content.children)) {
137
+ for (var _i = 0, _q = node.content.children; _i < _q.length; _i++) {
138
+ var child = _q[_i];
139
+ traverse(child, parentDataSource);
140
+ }
141
+ }
142
+ if ((_o = node.content) === null || _o === void 0 ? void 0 : _o.node) {
143
+ traverse(node.content.node, parentDataSource);
144
+ }
145
+ if ((_p = node.content) === null || _p === void 0 ? void 0 : _p.nodes) {
146
+ if (node.content.nodes.success) {
147
+ traverse(node.content.nodes.success, parentDataSource);
148
+ }
149
+ if (node.content.nodes.error) {
150
+ traverse(node.content.nodes.error, parentDataSource);
151
+ }
152
+ if (node.content.nodes.loading) {
153
+ traverse(node.content.nodes.loading, parentDataSource);
154
+ }
155
+ if (node.content.nodes.list) {
156
+ traverse(node.content.nodes.list, parentDataSource);
157
+ }
158
+ if (node.content.nodes.empty) {
159
+ traverse(node.content.nodes.empty, parentDataSource);
160
+ }
161
+ }
162
+ if (Array.isArray(node.children)) {
163
+ for (var _r = 0, _s = node.children; _r < _s.length; _r++) {
164
+ var child = _s[_r];
165
+ traverse(child, parentDataSource);
166
+ }
167
+ }
168
+ };
169
+ traverse(uidlNode);
170
+ return { usages: usages, byDataSourceId: byDataSourceId, byArrayMapperRenderProp: byArrayMapperRenderProp };
171
+ }
172
+ // Generate state variable names for a usage
173
+ function getStateVarsForUsage(usage) {
174
+ var idx = usage.index;
175
+ return {
176
+ pageStateVar: "ds_".concat(idx, "_page"),
177
+ setPageStateVar: "setDs_".concat(idx, "_page"),
178
+ maxPagesStateVar: "ds_".concat(idx, "_maxPages"),
179
+ setMaxPagesStateVar: "setDs_".concat(idx, "_maxPages"),
180
+ searchQueryVar: "ds_".concat(idx, "_searchQuery"),
181
+ setSearchQueryVar: "setDs_".concat(idx, "_searchQuery"),
182
+ debouncedSearchQueryVar: "ds_".concat(idx, "_debouncedQuery"),
183
+ setDebouncedSearchQueryVar: "setDs_".concat(idx, "_debouncedQuery"),
184
+ combinedStateVar: "ds_".concat(idx, "_state"),
185
+ setCombinedStateVar: "setDs_".concat(idx, "_state"),
186
+ skipDebounceRefVar: "ds_".concat(idx, "_skipDebounce"),
187
+ skipCountFetchRefVar: "ds_".concat(idx, "_skipCountFetch"),
188
+ propsPrefix: "".concat(usage.dataSourceIdentifier, "_ds_").concat(idx),
189
+ };
190
+ }
191
+ // ==================== MAIN PLUGIN ====================
50
192
  export var createNextArrayMapperPaginationPlugin = function () {
51
193
  var paginationPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () {
52
- var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, _a, paginatedMappers, searchOnlyMappers, paginationOnlyMappers, detectedPaginations, detectedSearchOnly, paginationInfos, getStaticPropsChunk, isPage, isComponent, opts, perPageMap, searchConfigMap, queryColumnsMap, stateDeclarations, hasSearchEnabled, firstReturnIndex, insertIndex, dataSourceToInfos_1, componentUseEffects_1, componentReturnIndex, componentEffectsInsertIndex_1, searchOnlyDataSources;
53
- var _b, _c, _d;
54
- return __generator(this, function (_e) {
194
+ var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, registry, getStaticPropsChunk, isPage, stateDeclarations, effectStatements, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, dataProvidersWithoutRepeaters, searchInputs, searchEnabledUsages, paginationNodes, paginatedUsages;
195
+ return __generator(this, function (_a) {
55
196
  uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options;
56
197
  componentChunk = chunks.find(function (chunk) { return chunk.name === 'jsx-component'; });
57
198
  if (!componentChunk || componentChunk.type !== ChunkType.AST) {
@@ -73,22 +214,19 @@ export var createNextArrayMapperPaginationPlugin = function () {
73
214
  return [2 /*return*/, structure];
74
215
  }
75
216
  blockStatement = arrowFunction.body;
76
- _a = detectPaginationsAndSearchFromJSX(blockStatement, uidl.node), paginatedMappers = _a.paginatedMappers, searchOnlyMappers = _a.searchOnlyMappers, paginationOnlyMappers = _a.paginationOnlyMappers;
77
- if (paginatedMappers.length === 0 &&
78
- searchOnlyMappers.length === 0 &&
79
- paginationOnlyMappers.length === 0) {
217
+ registry = buildStateRegistry(uidl.node);
218
+ if (registry.usages.length === 0) {
80
219
  return [2 /*return*/, structure];
81
220
  }
82
- detectedPaginations = __spreadArray(__spreadArray([], paginatedMappers, true), paginationOnlyMappers, true);
83
- detectedSearchOnly = searchOnlyMappers;
221
+ getStaticPropsChunk = chunks.find(function (chunk) { return chunk.name === 'getStaticProps'; });
222
+ isPage = !!getStaticPropsChunk;
223
+ // Add React dependencies
84
224
  if (!dependencies.useState) {
85
225
  dependencies.useState = {
86
226
  type: 'library',
87
227
  path: 'react',
88
228
  version: '',
89
- meta: {
90
- namedImport: true,
91
- },
229
+ meta: { namedImport: true },
92
230
  };
93
231
  }
94
232
  if (!dependencies.useMemo) {
@@ -96,9 +234,7 @@ export var createNextArrayMapperPaginationPlugin = function () {
96
234
  type: 'library',
97
235
  path: 'react',
98
236
  version: '',
99
- meta: {
100
- namedImport: true,
101
- },
237
+ meta: { namedImport: true },
102
238
  };
103
239
  }
104
240
  if (!dependencies.useCallback) {
@@ -106,9 +242,7 @@ export var createNextArrayMapperPaginationPlugin = function () {
106
242
  type: 'library',
107
243
  path: 'react',
108
244
  version: '',
109
- meta: {
110
- namedImport: true,
111
- },
245
+ meta: { namedImport: true },
112
246
  };
113
247
  }
114
248
  if (!dependencies.useRef) {
@@ -116,1474 +250,897 @@ export var createNextArrayMapperPaginationPlugin = function () {
116
250
  type: 'library',
117
251
  path: 'react',
118
252
  version: '',
119
- meta: {
120
- namedImport: true,
121
- },
253
+ meta: { namedImport: true },
254
+ };
255
+ }
256
+ if (!dependencies.useEffect) {
257
+ dependencies.useEffect = {
258
+ type: 'library',
259
+ path: 'react',
260
+ version: '',
261
+ meta: { namedImport: true },
122
262
  };
123
263
  }
124
264
  if (!componentChunk.meta) {
125
265
  componentChunk.meta = {};
126
266
  }
127
267
  componentChunk.meta.isClientComponent = true;
128
- paginationInfos = [];
129
- getStaticPropsChunk = chunks.find(function (chunk) { return chunk.name === 'getStaticProps'; });
130
- isPage = !!getStaticPropsChunk;
131
- isComponent = !isPage;
132
- opts = options;
133
- perPageMap = ((_b = opts.paginationConfig) === null || _b === void 0 ? void 0 : _b.perPageMap) || new Map();
134
- searchConfigMap = ((_c = opts.paginationConfig) === null || _c === void 0 ? void 0 : _c.searchConfigMap) || new Map();
135
- queryColumnsMap = ((_d = opts.paginationConfig) === null || _d === void 0 ? void 0 : _d.queryColumnsMap) || new Map();
136
268
  stateDeclarations = [];
137
- detectedPaginations.forEach(function (detected, index) {
138
- var paginationNodeId = "pg_".concat(index);
139
- // Use arrayMapperRenderProp if available, otherwise fall back to dataSourceIdentifier
140
- var lookupKey = detected.arrayMapperRenderProp || detected.dataSourceIdentifier;
141
- var perPage = perPageMap.get(lookupKey) || 10;
142
- var searchConfig = searchConfigMap.get(lookupKey);
143
- // queryColumns is keyed by dataSourceIdentifier, not array mapper render prop
144
- var queryColumns = queryColumnsMap.get(detected.dataSourceIdentifier);
145
- var info = generatePaginationLogic(paginationNodeId, detected.dataSourceIdentifier, perPage, searchConfig, queryColumns);
146
- paginationInfos.push(info);
147
- // Add refs to track first render for each useEffect (add first)
148
- if (info.searchEnabled) {
149
- var skipCountFetchOnMountRefVar = "skipCountFetchOnMount_pg_".concat(index);
150
- var skipCountFetchRefAST = types.variableDeclaration('const', [
151
- types.variableDeclarator(types.identifier(skipCountFetchOnMountRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
152
- ]);
153
- stateDeclarations.push(skipCountFetchRefAST);
154
- info.skipCountFetchOnMountRefVar = skipCountFetchOnMountRefVar;
155
- var skipDebounceOnMountRefVar = "skipDebounceOnMount_pg_".concat(index);
156
- var skipDebounceRefAST = types.variableDeclaration('const', [
157
- types.variableDeclarator(types.identifier(skipDebounceOnMountRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
158
- ]);
159
- stateDeclarations.push(skipDebounceRefAST);
160
- info.skipDebounceOnMountRefVar = skipDebounceOnMountRefVar;
269
+ effectStatements = [];
270
+ registry.usages.forEach(function (usage) {
271
+ if (usage.category === 'plain') {
272
+ return; // Plain mappers don't need state
161
273
  }
162
- // Add maxPages state
163
- var maxPagesStateVar = "".concat(info.pageStateVar.replace('_page', ''), "_maxPages");
164
- var setMaxPagesStateVar = "set".concat(maxPagesStateVar.charAt(0).toUpperCase() + maxPagesStateVar.slice(1));
165
- // For pages: initialize from props (with pagination-specific prop name), for components: initialize to 0
166
- var maxPagesInitValue = isPage
167
- ? types.logicalExpression('||', types.optionalMemberExpression(types.identifier('props'), types.identifier("".concat(info.dataSourceIdentifier, "_pg_").concat(index, "_maxPages")), false, true), types.numericLiteral(0))
168
- : types.numericLiteral(0);
169
- var maxPagesStateAST = types.variableDeclaration('const', [
170
- types.variableDeclarator(types.arrayPattern([
171
- types.identifier(maxPagesStateVar),
172
- types.identifier(setMaxPagesStateVar),
173
- ]), types.callExpression(types.identifier('useState'), [maxPagesInitValue])),
174
- ]);
175
- stateDeclarations.push(maxPagesStateAST);
176
- info.maxPagesStateVar = maxPagesStateVar;
177
- info.setMaxPagesStateVar = setMaxPagesStateVar;
178
- // If both pagination and search are enabled, combine them into a single state object
179
- if (info.searchEnabled && info.searchQueryVar && info.setSearchQueryVar) {
180
- // Combined state: { page: 1, debouncedQuery: '' }
181
- var combinedStateVar = "paginationState_pg_".concat(index);
182
- var setCombinedStateVar = "setPaginationState_pg_".concat(index);
183
- var combinedStateAST = types.variableDeclaration('const', [
274
+ var vars = getStateVarsForUsage(usage);
275
+ if (usage.category === 'paginated+search') {
276
+ // Combined state object for pagination + search
277
+ stateDeclarations.push(types.variableDeclaration('const', [
278
+ types.variableDeclarator(types.identifier(vars.skipDebounceRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
279
+ ]));
280
+ // Only add skipCountFetchRef for pages (where we have server-side count)
281
+ // For components, we need to fetch count on mount
282
+ if (isPage) {
283
+ stateDeclarations.push(types.variableDeclaration('const', [
284
+ types.variableDeclarator(types.identifier(vars.skipCountFetchRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
285
+ ]));
286
+ }
287
+ // maxPages state
288
+ var maxPagesInit = isPage
289
+ ? types.logicalExpression('||', types.optionalMemberExpression(types.identifier('props'), types.identifier("".concat(vars.propsPrefix, "_maxPages")), false, true), types.numericLiteral(0))
290
+ : types.numericLiteral(0);
291
+ stateDeclarations.push(types.variableDeclaration('const', [
184
292
  types.variableDeclarator(types.arrayPattern([
185
- types.identifier(combinedStateVar),
186
- types.identifier(setCombinedStateVar),
293
+ types.identifier(vars.maxPagesStateVar),
294
+ types.identifier(vars.setMaxPagesStateVar),
295
+ ]), types.callExpression(types.identifier('useState'), [maxPagesInit])),
296
+ ]));
297
+ // Combined state { page, debouncedQuery }
298
+ stateDeclarations.push(types.variableDeclaration('const', [
299
+ types.variableDeclarator(types.arrayPattern([
300
+ types.identifier(vars.combinedStateVar),
301
+ types.identifier(vars.setCombinedStateVar),
187
302
  ]), types.callExpression(types.identifier('useState'), [
188
303
  types.objectExpression([
189
304
  types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
190
305
  types.objectProperty(types.identifier('debouncedQuery'), types.stringLiteral('')),
191
306
  ]),
192
307
  ])),
193
- ]);
194
- stateDeclarations.push(combinedStateAST);
195
- // Still need the immediate search query state for the input
196
- var searchStateAST = types.variableDeclaration('const', [
308
+ ]));
309
+ // Immediate search query state
310
+ stateDeclarations.push(types.variableDeclaration('const', [
197
311
  types.variableDeclarator(types.arrayPattern([
198
- types.identifier(info.searchQueryVar),
199
- types.identifier(info.setSearchQueryVar),
312
+ types.identifier(vars.searchQueryVar),
313
+ types.identifier(vars.setSearchQueryVar),
200
314
  ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
201
- ]);
202
- stateDeclarations.push(searchStateAST);
203
- info.combinedStateVar = combinedStateVar;
204
- info.setCombinedStateVar = setCombinedStateVar;
205
- }
206
- else {
207
- // If search is not enabled, just add regular page state
208
- var pageStateAST = types.variableDeclaration('const', [
209
- types.variableDeclarator(types.arrayPattern([
210
- types.identifier(info.pageStateVar),
211
- types.identifier(info.setPageStateVar),
212
- ]), types.callExpression(types.identifier('useState'), [types.numericLiteral(1)])),
213
- ]);
214
- stateDeclarations.push(pageStateAST);
215
- }
216
- });
217
- // Add all state declarations at once to the beginning in correct order
218
- stateDeclarations.reverse().forEach(function (stateDecl) {
219
- blockStatement.body.unshift(stateDecl);
220
- });
221
- hasSearchEnabled = paginationInfos.some(function (info) { return info.searchEnabled; });
222
- if (hasSearchEnabled && !dependencies.useEffect) {
223
- dependencies.useEffect = {
224
- type: 'library',
225
- path: 'react',
226
- version: '',
227
- meta: {
228
- namedImport: true,
229
- },
230
- };
231
- }
232
- firstReturnIndex = blockStatement.body.findIndex(function (stmt) { return stmt.type === 'ReturnStatement'; });
233
- insertIndex = firstReturnIndex !== -1 ? firstReturnIndex : blockStatement.body.length;
234
- // Add effects in reverse order so they appear in correct order
235
- paginationInfos.forEach(function (info) {
236
- if (info.searchEnabled &&
237
- info.searchQueryVar &&
238
- info.debouncedSearchQueryVar &&
239
- info.setDebouncedSearchQueryVar) {
240
- // Add effect that updates debounced search after delay
241
- var skipDebounceOnMountRefVar = info.skipDebounceOnMountRefVar;
242
- var setCombinedStateVar = info.setCombinedStateVar;
243
- var debounceEffect = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
315
+ ]));
316
+ // Debounce effect
317
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
244
318
  types.arrowFunctionExpression([], types.blockStatement([
245
- types.ifStatement(types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.blockStatement([
246
- types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.booleanLiteral(false))),
319
+ types.ifStatement(types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.blockStatement([
320
+ types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.booleanLiteral(false))),
247
321
  types.returnStatement(),
248
322
  ])),
249
323
  types.variableDeclaration('const', [
250
324
  types.variableDeclarator(types.identifier('timer'), types.callExpression(types.identifier('setTimeout'), [
251
325
  types.arrowFunctionExpression([], types.blockStatement([
252
- types.expressionStatement(types.callExpression(types.identifier(setCombinedStateVar), [
326
+ types.expressionStatement(types.callExpression(types.identifier(vars.setCombinedStateVar), [
253
327
  types.objectExpression([
254
328
  types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
255
- types.objectProperty(types.identifier('debouncedQuery'), types.identifier(info.searchQueryVar)),
329
+ types.objectProperty(types.identifier('debouncedQuery'), types.identifier(vars.searchQueryVar)),
256
330
  ]),
257
331
  ])),
258
332
  ])),
259
- types.numericLiteral(info.searchDebounce || 300),
333
+ types.numericLiteral(usage.searchDebounce),
260
334
  ])),
261
335
  ]),
262
336
  types.returnStatement(types.arrowFunctionExpression([], types.callExpression(types.identifier('clearTimeout'), [
263
337
  types.identifier('timer'),
264
338
  ]))),
265
339
  ])),
266
- types.arrayExpression([types.identifier(info.searchQueryVar)]),
267
- ]));
268
- blockStatement.body.splice(insertIndex, 0, debounceEffect);
269
- // Add useEffect to refetch count when search changes (for both pages and components)
270
- var detected = detectedPaginations.find(function (d) { return d.dataSourceIdentifier === info.dataSourceIdentifier; });
271
- if (!detected) {
272
- return;
340
+ types.arrayExpression([types.identifier(vars.searchQueryVar)]),
341
+ ])));
342
+ // Count refetch effect
343
+ var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
344
+ var urlParams = [
345
+ types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery'))),
346
+ ];
347
+ if (usage.queryColumns.length > 0) {
348
+ urlParams.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
273
349
  }
274
- var resourceDefAttr = detected.dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'; });
275
- if (resourceDefAttr &&
276
- resourceDefAttr.value &&
277
- resourceDefAttr.value.type === 'JSXExpressionContainer') {
278
- var resourceDef = resourceDefAttr.value.expression;
279
- if (resourceDef.type === 'ObjectExpression') {
280
- var dataSourceIdProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'; });
281
- var tableNameProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'tableName'; });
282
- var dataSourceTypeProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'; });
283
- if (dataSourceIdProp && tableNameProp && dataSourceTypeProp) {
284
- var dataSourceId = dataSourceIdProp.value.value;
285
- var tableName = tableNameProp.value.value;
286
- var dataSourceType = dataSourceTypeProp.value.value;
287
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
288
- var setMaxPagesStateVar = info.setMaxPagesStateVar;
289
- // Create useEffect to refetch count when debounced search changes
290
- var skipCountFetchOnMountRefVar = info.skipCountFetchOnMountRefVar;
291
- var combinedStateVar = info.combinedStateVar;
292
- // Build URLSearchParams properties - query is always included, queryColumns is optional
293
- var urlSearchParamsProperties = [
294
- types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery'))),
295
- ];
296
- // Add queryColumns only if they exist
297
- if (info.queryColumns && info.queryColumns.length > 0) {
298
- urlSearchParamsProperties.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [
299
- types.arrayExpression(info.queryColumns.map(function (col) { return types.stringLiteral(col); })),
300
- ])));
301
- }
302
- var refetchCountEffect = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
303
- types.arrowFunctionExpression([], types.blockStatement([
304
- types.ifStatement(types.memberExpression(types.identifier(skipCountFetchOnMountRefVar), types.identifier('current')), types.blockStatement([
305
- types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(skipCountFetchOnMountRefVar), types.identifier('current')), types.booleanLiteral(false))),
306
- types.returnStatement(),
307
- ])),
308
- types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
309
- types.templateLiteral([
310
- types.templateElement({
311
- raw: "/api/".concat(fileName, "-count?"),
312
- cooked: "/api/".concat(fileName, "-count?"),
313
- }),
314
- types.templateElement({ raw: '', cooked: '' }),
315
- ], [
316
- types.newExpression(types.identifier('URLSearchParams'), [
317
- types.objectExpression(urlSearchParamsProperties),
318
- ]),
319
- ]),
320
- ]), types.identifier('then')), [
321
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
322
- ]), types.identifier('then')), [
323
- types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
324
- types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.binaryExpression('in', types.stringLiteral('count'), types.identifier('data'))), types.blockStatement([
325
- types.expressionStatement(types.callExpression(types.identifier(setMaxPagesStateVar), [
326
- types.conditionalExpression(types.binaryExpression('===', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(0)), types.numericLiteral(0), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
327
- types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(info.perPage)),
328
- ])),
329
- ])),
350
+ // Build the count fetch effect body
351
+ var countFetchEffectBody = [];
352
+ // Only add skip-on-mount check for pages (where we have server-side count)
353
+ if (isPage) {
354
+ countFetchEffectBody.push(types.ifStatement(types.memberExpression(types.identifier(vars.skipCountFetchRefVar), types.identifier('current')), types.blockStatement([
355
+ types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(vars.skipCountFetchRefVar), types.identifier('current')), types.booleanLiteral(false))),
356
+ types.returnStatement(),
357
+ ])));
358
+ }
359
+ // Add the fetch call
360
+ countFetchEffectBody.push(types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
361
+ types.templateLiteral([
362
+ types.templateElement({
363
+ raw: "/api/".concat(fileName, "-count?"),
364
+ cooked: "/api/".concat(fileName, "-count?"),
365
+ }),
366
+ types.templateElement({ raw: '', cooked: '' }),
367
+ ], [
368
+ types.newExpression(types.identifier('URLSearchParams'), [
369
+ types.objectExpression(urlParams),
370
+ ]),
371
+ ]),
372
+ ]), types.identifier('then')), [
373
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
374
+ ]), types.identifier('then')), [
375
+ types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
376
+ types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.binaryExpression('in', types.stringLiteral('count'), types.identifier('data'))), types.blockStatement([
377
+ types.expressionStatement(types.callExpression(types.identifier(vars.setMaxPagesStateVar), [
378
+ types.conditionalExpression(types.binaryExpression('===', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(0)), types.numericLiteral(0), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
379
+ types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(usage.perPage)),
380
+ ])),
381
+ ])),
382
+ ])),
383
+ ])),
384
+ ])));
385
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
386
+ types.arrowFunctionExpression([], types.blockStatement(countFetchEffectBody)),
387
+ types.arrayExpression([
388
+ types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')),
389
+ ]),
390
+ ])));
391
+ }
392
+ else if (usage.category === 'paginated-only') {
393
+ // Simple page state
394
+ var maxPagesInit = isPage
395
+ ? types.logicalExpression('||', types.optionalMemberExpression(types.identifier('props'), types.identifier("".concat(vars.propsPrefix, "_maxPages")), false, true), types.numericLiteral(0))
396
+ : types.numericLiteral(0);
397
+ stateDeclarations.push(types.variableDeclaration('const', [
398
+ types.variableDeclarator(types.arrayPattern([
399
+ types.identifier(vars.maxPagesStateVar),
400
+ types.identifier(vars.setMaxPagesStateVar),
401
+ ]), types.callExpression(types.identifier('useState'), [maxPagesInit])),
402
+ ]));
403
+ stateDeclarations.push(types.variableDeclaration('const', [
404
+ types.variableDeclarator(types.arrayPattern([
405
+ types.identifier(vars.pageStateVar),
406
+ types.identifier(vars.setPageStateVar),
407
+ ]), types.callExpression(types.identifier('useState'), [types.numericLiteral(1)])),
408
+ ]));
409
+ // For components (not pages), add a useEffect to fetch count on mount
410
+ // Pages get count from getStaticProps, but components need to fetch it client-side
411
+ if (!isPage) {
412
+ var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
413
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
414
+ types.arrowFunctionExpression([], types.blockStatement([
415
+ types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
416
+ types.stringLiteral("/api/".concat(fileName, "-count")),
417
+ ]), types.identifier('then')), [
418
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
419
+ ]), types.identifier('then')), [
420
+ types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
421
+ types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.binaryExpression('in', types.stringLiteral('count'), types.identifier('data'))), types.blockStatement([
422
+ types.expressionStatement(types.callExpression(types.identifier(vars.setMaxPagesStateVar), [
423
+ types.conditionalExpression(types.binaryExpression('===', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(0)), types.numericLiteral(0), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
424
+ types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(usage.perPage)),
330
425
  ])),
331
426
  ])),
332
427
  ])),
333
428
  ])),
334
- types.arrayExpression([
335
- types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery')),
336
- ]),
337
- ]));
338
- blockStatement.body.splice(insertIndex, 0, refetchCountEffect);
339
- }
340
- }
429
+ ])),
430
+ ])),
431
+ types.arrayExpression([]), // Empty dependency array - fetch on mount only
432
+ ])));
341
433
  }
342
434
  }
343
- });
344
- // For components, add useEffect to fetch count on mount
345
- if (isComponent) {
346
- if (!dependencies.useEffect) {
347
- dependencies.useEffect = {
348
- type: 'library',
349
- path: 'react',
350
- version: '',
351
- meta: {
352
- namedImport: true,
353
- },
354
- };
355
- }
356
- dataSourceToInfos_1 = new Map();
357
- paginationInfos.forEach(function (info) {
358
- var detected = detectedPaginations.find(function (d) { return d.dataSourceIdentifier === info.dataSourceIdentifier; });
359
- if (!detected) {
360
- return;
361
- }
362
- var resourceDefAttr = detected.dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'; });
363
- if (!resourceDefAttr ||
364
- !resourceDefAttr.value ||
365
- resourceDefAttr.value.type !== 'JSXExpressionContainer') {
366
- return;
367
- }
368
- var resourceDef = resourceDefAttr.value.expression;
369
- if (resourceDef.type !== 'ObjectExpression') {
370
- return;
371
- }
372
- var dataSourceIdProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'; });
373
- var tableNameProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'tableName'; });
374
- var dataSourceTypeProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'; });
375
- if (!dataSourceIdProp || !tableNameProp || !dataSourceTypeProp) {
376
- return;
377
- }
378
- var dataSourceId = dataSourceIdProp.value.value;
379
- var tableName = tableNameProp.value.value;
380
- var dataSourceType = dataSourceTypeProp.value.value;
381
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
382
- // Group by data source identifier
383
- if (!dataSourceToInfos_1.has(info.dataSourceIdentifier)) {
384
- dataSourceToInfos_1.set(info.dataSourceIdentifier, []);
385
- }
386
- dataSourceToInfos_1.get(info.dataSourceIdentifier).push({ info: info, detected: detected, fileName: fileName });
387
- });
388
- componentUseEffects_1 = [];
389
- dataSourceToInfos_1.forEach(function (infos) {
390
- var fileName = infos[0].fileName;
391
- // Create array of setState calls - one for each pagination using this data source
392
- var setStateStatements = infos.map(function (_a) {
393
- var info = _a.info;
394
- var setMaxPagesStateVar = info.setMaxPagesStateVar;
395
- return types.expressionStatement(types.callExpression(types.identifier(setMaxPagesStateVar), [
396
- types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
397
- types.binaryExpression('/', types.memberExpression(types.identifier('data'), types.identifier('count')), types.numericLiteral(info.perPage)),
398
- ]),
399
- ]));
400
- });
401
- // Create useEffect to fetch count on mount - sets ALL maxPages for this data source
402
- var useEffectAST = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
435
+ else if (usage.category === 'search-only') {
436
+ // Search-only state
437
+ stateDeclarations.push(types.variableDeclaration('const', [
438
+ types.variableDeclarator(types.identifier(vars.skipDebounceRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
439
+ ]));
440
+ stateDeclarations.push(types.variableDeclaration('const', [
441
+ types.variableDeclarator(types.arrayPattern([
442
+ types.identifier(vars.debouncedSearchQueryVar),
443
+ types.identifier(vars.setDebouncedSearchQueryVar),
444
+ ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
445
+ ]));
446
+ stateDeclarations.push(types.variableDeclaration('const', [
447
+ types.variableDeclarator(types.arrayPattern([
448
+ types.identifier(vars.searchQueryVar),
449
+ types.identifier(vars.setSearchQueryVar),
450
+ ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
451
+ ]));
452
+ // Debounce effect
453
+ effectStatements.push(types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
403
454
  types.arrowFunctionExpression([], types.blockStatement([
404
- types.expressionStatement(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
405
- types.stringLiteral("/api/".concat(fileName, "-count")),
406
- ]), types.identifier('then')), [
407
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
408
- ]), types.identifier('then')), [
409
- types.arrowFunctionExpression([types.identifier('data')], types.blockStatement([
410
- types.ifStatement(types.logicalExpression('&&', types.identifier('data'), types.memberExpression(types.identifier('data'), types.identifier('count'))), types.blockStatement(setStateStatements)),
411
- ])),
455
+ types.ifStatement(types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.blockStatement([
456
+ types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(vars.skipDebounceRefVar), types.identifier('current')), types.booleanLiteral(false))),
457
+ types.returnStatement(),
412
458
  ])),
459
+ types.variableDeclaration('const', [
460
+ types.variableDeclarator(types.identifier('timer'), types.callExpression(types.identifier('setTimeout'), [
461
+ types.arrowFunctionExpression([], types.blockStatement([
462
+ types.expressionStatement(types.callExpression(types.identifier(vars.setDebouncedSearchQueryVar), [types.identifier(vars.searchQueryVar)])),
463
+ ])),
464
+ types.numericLiteral(usage.searchDebounce),
465
+ ])),
466
+ ]),
467
+ types.returnStatement(types.arrowFunctionExpression([], types.callExpression(types.identifier('clearTimeout'), [
468
+ types.identifier('timer'),
469
+ ]))),
413
470
  ])),
414
- types.arrayExpression([]),
415
- ]));
416
- componentUseEffects_1.push(useEffectAST);
417
- });
418
- componentReturnIndex = blockStatement.body.findIndex(function (stmt) { return stmt.type === 'ReturnStatement'; });
419
- componentEffectsInsertIndex_1 = componentReturnIndex !== -1 ? componentReturnIndex : blockStatement.body.length;
420
- // Insert in reverse order to maintain correct order
421
- componentUseEffects_1.reverse().forEach(function (effect) {
422
- blockStatement.body.splice(componentEffectsInsertIndex_1, 0, effect);
423
- });
424
- }
425
- createAPIRoutesForPaginatedDataSources(uidl.node, options.dataSources, componentChunk, options.extractedResources, paginationInfos, isComponent);
426
- detectedPaginations.forEach(function (detected, index) {
427
- addPaginationParamsToDataProvider(detected.dataProviderJSX, paginationInfos[index], index);
471
+ types.arrayExpression([types.identifier(vars.searchQueryVar)]),
472
+ ])));
473
+ }
474
+ });
475
+ // Insert state declarations at the beginning
476
+ stateDeclarations.reverse().forEach(function (s) { return blockStatement.body.unshift(s); });
477
+ returnIndex = blockStatement.body.findIndex(function (s) { return s.type === 'ReturnStatement'; });
478
+ insertIndex = returnIndex !== -1 ? returnIndex : blockStatement.body.length;
479
+ effectStatements.reverse().forEach(function (e) { return blockStatement.body.splice(insertIndex, 0, e); });
480
+ dataProviders = findAllDataProvidersInJSX(blockStatement);
481
+ dataProvidersWithRepeaters = dataProviders.filter(function (dp) {
482
+ var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
483
+ return hasRepeater;
484
+ });
485
+ usageIndexByDataSourceId = new Map();
486
+ dataProvidersWithRepeaters.forEach(function (dp) {
487
+ var _a, _b;
488
+ var nameAttr = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
489
+ if (!((_b = (_a = nameAttr === null || nameAttr === void 0 ? void 0 : nameAttr.value) === null || _a === void 0 ? void 0 : _a.expression) === null || _b === void 0 ? void 0 : _b.value)) {
490
+ return;
491
+ }
492
+ var dataSourceIdentifier = nameAttr.value.expression.value;
493
+ // Use pure order-based matching within each dataSourceIdentifier
494
+ var usages = registry.byDataSourceId.get(dataSourceIdentifier) || [];
495
+ var currentIndex = usageIndexByDataSourceId.get(dataSourceIdentifier) || 0;
496
+ if (currentIndex >= usages.length) {
497
+ return;
498
+ }
499
+ var usage = usages[currentIndex];
500
+ usageIndexByDataSourceId.set(dataSourceIdentifier, currentIndex + 1);
501
+ var vars = getStateVarsForUsage(usage);
502
+ var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
503
+ // Update DataProvider based on category
504
+ if (usage.category === 'paginated+search') {
505
+ updateDataProviderForPaginatedSearch(dp, usage, vars, fileName);
506
+ }
507
+ else if (usage.category === 'paginated-only') {
508
+ updateDataProviderForPaginationOnly(dp, usage, vars, fileName);
509
+ }
510
+ else if (usage.category === 'search-only') {
511
+ updateDataProviderForSearchOnly(dp, usage, vars, fileName);
512
+ }
513
+ else {
514
+ updateDataProviderForPlain(dp, vars);
515
+ }
516
+ // Create API route if needed
517
+ if (usage.category !== 'plain') {
518
+ ensureAPIRouteExists(options.extractedResources, usage);
519
+ }
428
520
  });
429
- modifyPaginationButtons(blockStatement, detectedPaginations, paginationInfos);
430
- modifySearchInputs(blockStatement, detectedPaginations, paginationInfos);
521
+ dataProvidersWithoutRepeaters = dataProviders.filter(function (dp) {
522
+ var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
523
+ return !hasRepeater;
524
+ });
525
+ dataProvidersWithoutRepeaters.forEach(function (dp) {
526
+ stabilizeDataProviderWithoutRepeater(dp);
527
+ });
528
+ searchInputs = findAllSearchInputsInJSX(blockStatement);
529
+ searchEnabledUsages = registry.usages.filter(function (u) { return u.searchEnabled; });
530
+ // Match by order - search input 0 -> searchEnabledUsages[0], etc.
531
+ searchInputs.forEach(function (input, idx) {
532
+ if (idx >= searchEnabledUsages.length) {
533
+ return;
534
+ }
535
+ var usage = searchEnabledUsages[idx];
536
+ var vars = getStateVarsForUsage(usage);
537
+ wireSearchInput(input.node, vars);
538
+ });
539
+ paginationNodes = findAllPaginationNodesInJSX(blockStatement);
540
+ paginatedUsages = registry.usages.filter(function (u) { return u.paginated; });
541
+ // Match by order - pagination node 0 -> paginatedUsages[0], etc.
542
+ paginationNodes.forEach(function (paginationNode, idx) {
543
+ if (idx >= paginatedUsages.length) {
544
+ return;
545
+ }
546
+ var usage = paginatedUsages[idx];
547
+ var vars = getStateVarsForUsage(usage);
548
+ wirePaginationButtons(paginationNode.node, usage, vars);
549
+ });
550
+ // STEP 6: Update getStaticProps if this is a page
431
551
  if (isPage) {
432
- modifyGetStaticPropsForPagination(chunks, paginationInfos);
433
- }
434
- searchOnlyDataSources = detectedSearchOnly;
435
- if (searchOnlyDataSources.length > 0) {
436
- handleSearchOnlyArrayMappers(blockStatement, searchOnlyDataSources, searchConfigMap, queryColumnsMap, dependencies);
437
- // Create API routes for search-only data sources
438
- createAPIRoutesForSearchOnlyDataSources(uidl.node, options.dataSources, componentChunk, options.extractedResources, searchOnlyDataSources);
552
+ updateGetStaticProps(chunks, registry);
439
553
  }
440
554
  return [2 /*return*/, structure];
441
555
  });
442
556
  }); };
443
557
  return paginationPlugin;
444
558
  };
445
- function findParentNode(root, target, currentParent) {
446
- if (currentParent === void 0) { currentParent = null; }
447
- if (!root || !target) {
448
- return null;
449
- }
450
- if (root === target) {
451
- return currentParent;
452
- }
453
- if (root.type === 'JSXElement' || root.type === 'JSXFragment') {
454
- if (root.children && Array.isArray(root.children)) {
455
- for (var _i = 0, _a = root.children; _i < _a.length; _i++) {
456
- var child = _a[_i];
457
- var found = findParentNode(child, target, root);
458
- if (found !== null) {
459
- return found;
460
- }
461
- }
559
+ // ==================== HELPER FUNCTIONS ====================
560
+ function findAllDataProvidersInJSX(blockStatement) {
561
+ var results = [];
562
+ var traverse = function (node) {
563
+ var _a, _b;
564
+ if (!node) {
565
+ return;
462
566
  }
463
- }
464
- else if (root.type === 'JSXExpressionContainer') {
465
- if (root.expression) {
466
- var found = findParentNode(root.expression, target, root);
467
- if (found !== null) {
468
- return found;
469
- }
567
+ if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'DataProvider') {
568
+ results.push(node);
470
569
  }
471
- }
472
- else if (root.type === 'BlockStatement') {
473
- if (root.body && Array.isArray(root.body)) {
474
- for (var _b = 0, _c = root.body; _b < _c.length; _b++) {
475
- var stmt = _c[_b];
476
- var found = findParentNode(stmt, target, root);
477
- if (found !== null) {
478
- return found;
479
- }
480
- }
570
+ if (node.children && Array.isArray(node.children)) {
571
+ node.children.forEach(function (c) { return traverse(c); });
481
572
  }
482
- }
483
- else if (root.type === 'ReturnStatement') {
484
- if (root.argument) {
485
- var found = findParentNode(root.argument, target, root);
486
- if (found !== null) {
487
- return found;
573
+ if (node.body) {
574
+ if (Array.isArray(node.body)) {
575
+ node.body.forEach(function (s) { return traverse(s); });
576
+ }
577
+ else {
578
+ traverse(node.body);
488
579
  }
489
580
  }
490
- }
491
- else if (root.type === 'ConditionalExpression') {
492
- var foundConsequent = findParentNode(root.consequent, target, root);
493
- if (foundConsequent !== null) {
494
- return foundConsequent;
581
+ if (node.consequent) {
582
+ traverse(node.consequent);
495
583
  }
496
- var foundAlternate = findParentNode(root.alternate, target, root);
497
- if (foundAlternate !== null) {
498
- return foundAlternate;
584
+ if (node.alternate) {
585
+ traverse(node.alternate);
499
586
  }
500
- }
501
- return null;
587
+ if (node.expression) {
588
+ traverse(node.expression);
589
+ }
590
+ if (node.argument) {
591
+ traverse(node.argument);
592
+ }
593
+ if (node.arguments) {
594
+ node.arguments.forEach(function (a) { return traverse(a); });
595
+ }
596
+ };
597
+ traverse(blockStatement);
598
+ return results;
502
599
  }
503
- function detectPaginationsAndSearchFromJSX(blockStatement, uidlNode) {
504
- var dataProviderList = [];
505
- var arrayMapperInfoMap = new Map();
506
- if (uidlNode) {
507
- var collectArrayMapperInfo_1 = function (node) {
508
- var _a, _b, _c, _d, _e;
509
- if (!node) {
510
- return;
511
- }
512
- if (node.type === 'data-source-list' && ((_a = node.content) === null || _a === void 0 ? void 0 : _a.renderPropIdentifier)) {
513
- var dataSourceIdentifier_1 = node.content.renderPropIdentifier;
514
- if ((_d = (_c = (_b = node.content.nodes) === null || _b === void 0 ? void 0 : _b.success) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.children) {
515
- node.content.nodes.success.content.children.forEach(function (child) {
516
- var _a;
517
- if (child.type === 'cms-list-repeater' && ((_a = child.content) === null || _a === void 0 ? void 0 : _a.renderPropIdentifier)) {
518
- var arrayMapperRenderProp = child.content.renderPropIdentifier;
519
- // Key by array mapper render prop (unique), not data source identifier
520
- arrayMapperInfoMap.set(arrayMapperRenderProp, {
521
- dataSourceIdentifier: dataSourceIdentifier_1,
522
- renderProp: arrayMapperRenderProp,
523
- paginated: child.content.paginated || false,
524
- searchEnabled: child.content.searchEnabled || false,
525
- });
526
- }
527
- });
528
- }
529
- }
530
- if ((_e = node.content) === null || _e === void 0 ? void 0 : _e.children) {
531
- node.content.children.forEach(function (child) { return collectArrayMapperInfo_1(child); });
532
- }
533
- if (node.children && Array.isArray(node.children)) {
534
- node.children.forEach(function (child) { return collectArrayMapperInfo_1(child); });
535
- }
536
- };
537
- collectArrayMapperInfo_1(uidlNode);
600
+ function findArrayMapperRenderPropInDataProvider(dataProvider) {
601
+ var _a, _b, _c, _d, _e;
602
+ var renderSuccessAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderSuccess'; });
603
+ if (!((_a = renderSuccessAttr === null || renderSuccessAttr === void 0 ? void 0 : renderSuccessAttr.value) === null || _a === void 0 ? void 0 : _a.expression)) {
604
+ return undefined;
538
605
  }
539
- var dataProvidersWithParents = [];
540
- var findDataProvidersAndParents = function (node, parent) {
606
+ var findRepeater = function (node) {
541
607
  var _a, _b;
542
- if (parent === void 0) { parent = null; }
543
608
  if (!node) {
544
- return;
609
+ return null;
545
610
  }
546
- // Check if this is a DataProvider
547
- if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'DataProvider') {
548
- dataProvidersWithParents.push({
549
- dataProvider: node,
550
- parent: parent,
551
- });
611
+ if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'Repeater') {
612
+ return node;
552
613
  }
553
- // Only recurse through JSX structure, not into embedded expressions or code
554
- if (node.type === 'ReturnStatement' && node.argument) {
555
- findDataProvidersAndParents(node.argument, parent);
614
+ if (node.body) {
615
+ return findRepeater(node.body);
556
616
  }
557
- else if (node.type === 'JSXElement' || node.type === 'JSXFragment') {
558
- // Recurse through JSX children
559
- if (node.children && Array.isArray(node.children)) {
560
- node.children.forEach(function (child) { return findDataProvidersAndParents(child, node); });
617
+ if (node.children && Array.isArray(node.children)) {
618
+ for (var _i = 0, _c = node.children; _i < _c.length; _i++) {
619
+ var c = _c[_i];
620
+ var r = findRepeater(c);
621
+ if (r) {
622
+ return r;
623
+ }
561
624
  }
562
625
  }
563
- else if (node.type === 'JSXExpressionContainer') {
564
- // For expression containers, continue but don't go into the expression itself
565
- if (node.expression &&
566
- (node.expression.type === 'JSXElement' || node.expression.type === 'JSXFragment')) {
567
- findDataProvidersAndParents(node.expression, parent);
568
- }
626
+ return null;
627
+ };
628
+ var repeater = findRepeater(renderSuccessAttr.value.expression);
629
+ if (!repeater) {
630
+ return undefined;
631
+ }
632
+ var renderItemAttr = repeater.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderItem'; });
633
+ if (!((_e = (_d = (_c = (_b = renderItemAttr === null || renderItemAttr === void 0 ? void 0 : renderItemAttr.value) === null || _b === void 0 ? void 0 : _b.expression) === null || _c === void 0 ? void 0 : _c.params) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.name)) {
634
+ return undefined;
635
+ }
636
+ return renderItemAttr.value.expression.params[0].name;
637
+ }
638
+ function findAllSearchInputsInJSX(blockStatement) {
639
+ var results = [];
640
+ var traverse = function (node) {
641
+ var _a, _b, _c, _d, _e, _f;
642
+ if (!node) {
643
+ return;
569
644
  }
570
- else if (node.type === 'BlockStatement') {
571
- // For block statements (function bodies), look through body array
572
- if (node.body && Array.isArray(node.body)) {
573
- node.body.forEach(function (stmt) { return findDataProvidersAndParents(stmt, node); });
645
+ if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'input') {
646
+ var classAttr = (_c = node.openingElement.attributes) === null || _c === void 0 ? void 0 : _c.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
647
+ var className = ((_d = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _d === void 0 ? void 0 : _d.value) || ((_f = (_e = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _e === void 0 ? void 0 : _e.expression) === null || _f === void 0 ? void 0 : _f.value) || '';
648
+ if (className.includes('search-input')) {
649
+ results.push({ node: node, className: className });
574
650
  }
575
651
  }
576
- else if (node.type === 'ConditionalExpression') {
577
- // Check both branches of conditional
578
- findDataProvidersAndParents(node.consequent, parent);
579
- findDataProvidersAndParents(node.alternate, parent);
652
+ if (node.children && Array.isArray(node.children)) {
653
+ node.children.forEach(function (c) { return traverse(c); });
580
654
  }
581
- };
582
- findDataProvidersAndParents(blockStatement);
583
- // Now process each DataProvider and find its siblings
584
- dataProvidersWithParents.forEach(function (_a) {
585
- var _b, _c;
586
- var dataProvider = _a.dataProvider, parent = _a.parent;
587
- var nameAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
588
- // Find the array mapper render prop by looking inside renderSuccess -> Repeater -> renderItem param
589
- var renderSuccessAttr = dataProvider.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderSuccess'; });
590
- var arrayMapperRenderProp;
591
- if (renderSuccessAttr && ((_b = renderSuccessAttr.value) === null || _b === void 0 ? void 0 : _b.type) === 'JSXExpressionContainer') {
592
- var renderFunc = renderSuccessAttr.value.expression;
593
- if (renderFunc.type === 'ArrowFunctionExpression') {
594
- // Look for Repeater inside the render function
595
- var findRepeater_1 = function (node) {
596
- var _a, _b;
597
- if (!node) {
598
- return null;
599
- }
600
- if (node.type === 'JSXElement' && ((_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.name) === 'Repeater') {
601
- return node;
602
- }
603
- if (node.body) {
604
- return findRepeater_1(node.body);
605
- }
606
- if (node.children && Array.isArray(node.children)) {
607
- for (var _i = 0, _c = node.children; _i < _c.length; _i++) {
608
- var child = _c[_i];
609
- var result = findRepeater_1(child);
610
- if (result) {
611
- return result;
612
- }
613
- }
614
- }
615
- if (node.type === 'JSXFragment' || node.type === 'JSXElement') {
616
- if (node.children && Array.isArray(node.children)) {
617
- for (var _d = 0, _e = node.children; _d < _e.length; _d++) {
618
- var child = _e[_d];
619
- var result = findRepeater_1(child);
620
- if (result) {
621
- return result;
622
- }
623
- }
624
- }
625
- }
626
- if (node.type === 'JSXExpressionContainer') {
627
- return findRepeater_1(node.expression);
628
- }
629
- if (node.expression) {
630
- return findRepeater_1(node.expression);
631
- }
632
- if (node.consequent) {
633
- var result = findRepeater_1(node.consequent);
634
- if (result) {
635
- return result;
636
- }
637
- }
638
- if (node.alternate) {
639
- return findRepeater_1(node.alternate);
640
- }
641
- return null;
642
- };
643
- var repeater = findRepeater_1(renderFunc);
644
- if (repeater) {
645
- // Find renderItem attribute on Repeater
646
- var renderItemAttr = repeater.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'renderItem'; });
647
- if (renderItemAttr && ((_c = renderItemAttr.value) === null || _c === void 0 ? void 0 : _c.type) === 'JSXExpressionContainer') {
648
- var renderItemFunc = renderItemAttr.value.expression;
649
- if (renderItemFunc.type === 'ArrowFunctionExpression' &&
650
- renderItemFunc.params &&
651
- renderItemFunc.params.length > 0) {
652
- var param = renderItemFunc.params[0];
653
- if (param.type === 'Identifier') {
654
- arrayMapperRenderProp = param.name;
655
- }
656
- }
657
- }
658
- }
655
+ if (node.body) {
656
+ if (Array.isArray(node.body)) {
657
+ node.body.forEach(function (s) { return traverse(s); });
658
+ }
659
+ else {
660
+ traverse(node.body);
659
661
  }
660
662
  }
661
- if (!nameAttr ||
662
- !nameAttr.value ||
663
- nameAttr.value.type !== 'JSXExpressionContainer' ||
664
- !arrayMapperRenderProp) {
663
+ if (node.consequent) {
664
+ traverse(node.consequent);
665
+ }
666
+ if (node.alternate) {
667
+ traverse(node.alternate);
668
+ }
669
+ if (node.expression) {
670
+ traverse(node.expression);
671
+ }
672
+ if (node.argument) {
673
+ traverse(node.argument);
674
+ }
675
+ };
676
+ traverse(blockStatement);
677
+ return results;
678
+ }
679
+ function findAllPaginationNodesInJSX(blockStatement) {
680
+ var results = [];
681
+ var traverse = function (node) {
682
+ var _a, _b, _c, _d, _e;
683
+ if (!node) {
665
684
  return;
666
685
  }
667
- var dataProviderIdentifier = nameAttr.value.expression.value;
668
- var paginationNodeInfo = null;
669
- var searchInputInfo = null;
670
- var findSearchAndPaginationInScope = function (scopeNode, skipNode) {
671
- var _a, _b, _c, _d, _e, _f;
672
- if (skipNode === void 0) { skipNode = null; }
673
- if (!scopeNode || !scopeNode.children || !Array.isArray(scopeNode.children)) {
674
- return false;
686
+ if (node.type === 'JSXElement') {
687
+ var classAttr = (_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
688
+ var className = ((_c = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _c === void 0 ? void 0 : _c.value) || ((_e = (_d = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _d === void 0 ? void 0 : _d.expression) === null || _e === void 0 ? void 0 : _e.value) || '';
689
+ if (className.includes('cms-pagination-node')) {
690
+ results.push({ node: node, className: className });
675
691
  }
676
- var foundSomething = false;
677
- for (var _i = 0, _g = scopeNode.children; _i < _g.length; _i++) {
678
- var child = _g[_i];
679
- if (child === skipNode) {
680
- continue;
681
- }
682
- if (child.type === 'JSXElement') {
683
- var childClassName = getClassName(((_a = child.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) || []);
684
- var childElementName = (_c = (_b = child.openingElement) === null || _b === void 0 ? void 0 : _b.name) === null || _c === void 0 ? void 0 : _c.name;
685
- // Found pagination node
686
- if (childClassName && childClassName.includes('cms-pagination-node')) {
687
- var prevClass = findChildWithClass(child, 'previous');
688
- var nextClass = findChildWithClass(child, 'next');
689
- if (prevClass || nextClass) {
690
- paginationNodeInfo = {
691
- class: childClassName,
692
- prevClass: prevClass,
693
- nextClass: nextClass,
694
- };
695
- foundSomething = true;
696
- }
697
- }
698
- // Found search container - search for input inside it
699
- if (childClassName && childClassName.includes('data-source-search-node')) {
700
- if (child.children && Array.isArray(child.children)) {
701
- for (var _h = 0, _j = child.children; _h < _j.length; _h++) {
702
- var searchChild = _j[_h];
703
- if (searchChild.type === 'JSXElement') {
704
- var searchChildElementName = (_e = (_d = searchChild.openingElement) === null || _d === void 0 ? void 0 : _d.name) === null || _e === void 0 ? void 0 : _e.name;
705
- var searchChildClassName = getClassName(((_f = searchChild.openingElement) === null || _f === void 0 ? void 0 : _f.attributes) || []);
706
- if (searchChildClassName &&
707
- searchChildClassName.includes('search-input') &&
708
- searchChildElementName === 'input') {
709
- searchInputInfo = {
710
- class: searchChildClassName,
711
- jsx: searchChild,
712
- };
713
- foundSomething = true;
714
- }
715
- }
716
- }
717
- }
718
- }
719
- // Also check if search input is a direct child
720
- if (childClassName &&
721
- childClassName.includes('search-input') &&
722
- childElementName === 'input') {
723
- searchInputInfo = {
724
- class: childClassName,
725
- jsx: child,
726
- };
727
- foundSomething = true;
728
- }
729
- // Stop searching if we found both or if we found what we're looking for
730
- if (foundSomething && (searchInputInfo || paginationNodeInfo)) {
731
- return true;
732
- }
733
- // Only recurse if we haven't found what we're looking for yet
734
- if (!searchInputInfo || !paginationNodeInfo) {
735
- if (findSearchAndPaginationInScope(child, skipNode)) {
736
- return true;
737
- }
738
- }
739
- }
692
+ }
693
+ if (node.children && Array.isArray(node.children)) {
694
+ node.children.forEach(function (c) { return traverse(c); });
695
+ }
696
+ if (node.body) {
697
+ if (Array.isArray(node.body)) {
698
+ node.body.forEach(function (s) { return traverse(s); });
740
699
  }
741
- return foundSomething;
742
- };
743
- var currentScope = parent;
744
- var depth = 0;
745
- var maxDepth = 5;
746
- while (currentScope && (!searchInputInfo || !paginationNodeInfo) && depth < maxDepth) {
747
- var found = findSearchAndPaginationInScope(currentScope, depth === 0 ? dataProvider : null);
748
- // Stop searching up the tree if we found a pagination node at this level
749
- if (found && paginationNodeInfo) {
750
- break;
700
+ else {
701
+ traverse(node.body);
751
702
  }
752
- currentScope = findParentNode(blockStatement, currentScope);
753
- depth++;
754
703
  }
755
- // Record the DataProvider with its pagination/search info
756
- // Use array instead of Map to handle multiple DataProviders with same name
757
- dataProviderList.push({
758
- identifier: dataProviderIdentifier,
759
- dataProvider: dataProvider,
760
- arrayMapperRenderProp: arrayMapperRenderProp,
761
- paginationNode: paginationNodeInfo || undefined,
762
- searchInput: searchInputInfo || undefined,
763
- hasPagination: !!paginationNodeInfo,
764
- hasSearch: !!searchInputInfo,
765
- });
766
- });
767
- // Categorize data providers
768
- var paginatedMappers = [];
769
- var searchOnlyMappers = [];
770
- var paginationOnlyMappers = [];
771
- var plainMappers = [];
772
- dataProviderList.forEach(function (info) {
773
- var _a, _b, _c, _d;
774
- // Check UIDL flags for this array mapper
775
- var uidlInfo = info.arrayMapperRenderProp
776
- ? arrayMapperInfoMap.get(info.arrayMapperRenderProp)
777
- : null;
778
- // Only process pagination/search if UIDL explicitly enables it
779
- var shouldHavePagination = (uidlInfo === null || uidlInfo === void 0 ? void 0 : uidlInfo.paginated) && info.hasPagination;
780
- var shouldHaveSearch = (uidlInfo === null || uidlInfo === void 0 ? void 0 : uidlInfo.searchEnabled) && info.hasSearch;
781
- if (shouldHavePagination && shouldHaveSearch) {
782
- // Pagination + Search
783
- paginatedMappers.push({
784
- paginationNodeClass: info.paginationNode.class,
785
- prevButtonClass: info.paginationNode.prevClass,
786
- nextButtonClass: info.paginationNode.nextClass,
787
- dataSourceIdentifier: info.identifier,
788
- dataProviderJSX: info.dataProvider,
789
- arrayMapperRenderProp: info.arrayMapperRenderProp,
790
- searchInputClass: (_a = info.searchInput) === null || _a === void 0 ? void 0 : _a.class,
791
- searchInputJSX: (_b = info.searchInput) === null || _b === void 0 ? void 0 : _b.jsx,
792
- });
704
+ if (node.consequent) {
705
+ traverse(node.consequent);
793
706
  }
794
- else if (shouldHavePagination && !shouldHaveSearch) {
795
- // Pagination only
796
- paginationOnlyMappers.push({
797
- paginationNodeClass: info.paginationNode.class,
798
- prevButtonClass: info.paginationNode.prevClass,
799
- nextButtonClass: info.paginationNode.nextClass,
800
- dataSourceIdentifier: info.identifier,
801
- dataProviderJSX: info.dataProvider,
802
- arrayMapperRenderProp: info.arrayMapperRenderProp,
803
- searchInputClass: undefined,
804
- searchInputJSX: undefined,
805
- });
707
+ if (node.alternate) {
708
+ traverse(node.alternate);
806
709
  }
807
- else if (!shouldHavePagination && shouldHaveSearch) {
808
- // Search only
809
- searchOnlyMappers.push({
810
- paginationNodeClass: '',
811
- prevButtonClass: null,
812
- nextButtonClass: null,
813
- dataSourceIdentifier: info.identifier,
814
- dataProviderJSX: info.dataProvider,
815
- arrayMapperRenderProp: info.arrayMapperRenderProp,
816
- searchInputClass: (_c = info.searchInput) === null || _c === void 0 ? void 0 : _c.class,
817
- searchInputJSX: (_d = info.searchInput) === null || _d === void 0 ? void 0 : _d.jsx,
818
- });
710
+ if (node.expression) {
711
+ traverse(node.expression);
819
712
  }
820
- else {
821
- // Plain (no pagination, no search) - UIDL doesn't enable it or no controls found
822
- plainMappers.push({
823
- paginationNodeClass: '',
824
- prevButtonClass: null,
825
- nextButtonClass: null,
826
- dataSourceIdentifier: info.identifier,
827
- dataProviderJSX: info.dataProvider,
828
- arrayMapperRenderProp: info.arrayMapperRenderProp,
829
- searchInputClass: undefined,
830
- searchInputJSX: undefined,
831
- });
713
+ if (node.argument) {
714
+ traverse(node.argument);
832
715
  }
833
- });
834
- return { paginatedMappers: paginatedMappers, searchOnlyMappers: searchOnlyMappers, paginationOnlyMappers: paginationOnlyMappers, plainMappers: plainMappers };
716
+ };
717
+ traverse(blockStatement);
718
+ return results;
835
719
  }
836
- function handleSearchOnlyArrayMappers(blockStatement, searchOnlyDataSources, searchConfigMap, queryColumnsMap, dependencies) {
837
- var searchOnlyStates = [];
838
- var searchOnlyEffects = [];
839
- searchOnlyDataSources.forEach(function (detected, index) {
840
- var searchId = "search_".concat(index);
841
- var searchQueryVar = "".concat(searchId, "_query");
842
- var setSearchQueryVar = "set".concat(searchQueryVar.charAt(0).toUpperCase() + searchQueryVar.slice(1));
843
- var debouncedSearchQueryVar = "debounced".concat(searchQueryVar.charAt(0).toUpperCase() + searchQueryVar.slice(1));
844
- var setDebouncedSearchQueryVar = "set".concat(debouncedSearchQueryVar.charAt(0).toUpperCase() + debouncedSearchQueryVar.slice(1));
845
- var skipDebounceOnMountRefVar = "skipDebounceOnMount".concat(searchId);
846
- var searchConfig = searchConfigMap.get(detected.dataSourceIdentifier);
847
- var searchDebounce = (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.searchDebounce) || 300;
848
- var queryColumns = queryColumnsMap.get(detected.dataSourceIdentifier);
849
- // Add skip ref
850
- var skipRefAST = types.variableDeclaration('const', [
851
- types.variableDeclarator(types.identifier(skipDebounceOnMountRefVar), types.callExpression(types.identifier('useRef'), [types.booleanLiteral(true)])),
852
- ]);
853
- searchOnlyStates.push(skipRefAST);
854
- // Add debounced search state
855
- var debouncedSearchStateAST = types.variableDeclaration('const', [
856
- types.variableDeclarator(types.arrayPattern([
857
- types.identifier(debouncedSearchQueryVar),
858
- types.identifier(setDebouncedSearchQueryVar),
859
- ]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
860
- ]);
861
- searchOnlyStates.push(debouncedSearchStateAST);
862
- // Add search query state
863
- var searchStateAST = types.variableDeclaration('const', [
864
- types.variableDeclarator(types.arrayPattern([types.identifier(searchQueryVar), types.identifier(setSearchQueryVar)]), types.callExpression(types.identifier('useState'), [types.stringLiteral('')])),
865
- ]);
866
- searchOnlyStates.push(searchStateAST);
867
- // Add useEffect for debouncing
868
- if (!dependencies.useEffect) {
869
- dependencies.useEffect = {
870
- type: 'library',
871
- path: 'react',
872
- version: '',
873
- meta: {
874
- namedImport: true,
875
- },
876
- };
877
- }
878
- var debounceEffect = types.expressionStatement(types.callExpression(types.identifier('useEffect'), [
879
- types.arrowFunctionExpression([], types.blockStatement([
880
- types.ifStatement(types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.blockStatement([
881
- types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier(skipDebounceOnMountRefVar), types.identifier('current')), types.booleanLiteral(false))),
882
- types.returnStatement(),
883
- ])),
884
- types.variableDeclaration('const', [
885
- types.variableDeclarator(types.identifier('timer'), types.callExpression(types.identifier('setTimeout'), [
886
- types.arrowFunctionExpression([], types.blockStatement([
887
- types.expressionStatement(types.callExpression(types.identifier(setDebouncedSearchQueryVar), [
888
- types.identifier(searchQueryVar),
889
- ])),
890
- ])),
891
- types.numericLiteral(searchDebounce),
892
- ])),
893
- ]),
894
- types.returnStatement(types.arrowFunctionExpression([], types.callExpression(types.identifier('clearTimeout'), [types.identifier('timer')]))),
895
- ])),
896
- types.arrayExpression([types.identifier(searchQueryVar)]),
897
- ]));
898
- searchOnlyEffects.push(debounceEffect);
899
- // Modify DataProvider to include search params (even without queryColumns)
900
- if (detected.dataProviderJSX) {
901
- addSearchParamsToDataProvider(detected.dataProviderJSX, {
902
- debouncedSearchQueryVar: debouncedSearchQueryVar,
903
- queryColumns: queryColumns || [],
904
- });
905
- }
906
- // Modify search input
907
- if (detected.searchInputJSX) {
908
- addSearchInputHandlers(detected.searchInputJSX, {
909
- searchQueryVar: searchQueryVar,
910
- setSearchQueryVar: setSearchQueryVar,
911
- searchEnabled: true,
912
- });
913
- }
914
- });
915
- // Add all state declarations at the beginning in correct order
916
- searchOnlyStates.reverse().forEach(function (stateDecl) {
917
- blockStatement.body.unshift(stateDecl);
720
+ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
721
+ var attrs = dp.openingElement.attributes;
722
+ // Remove existing params, key, initialData, fetchData, persistDataDuringLoading
723
+ dp.openingElement.attributes = attrs.filter(function (attr) {
724
+ var _a;
725
+ return !['params', 'key', 'initialData', 'fetchData', 'persistDataDuringLoading'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name);
918
726
  });
919
- // Recalculate insertIndex after adding states (since unshift shifted everything)
920
- var newInsertIndex = blockStatement.body.findIndex(function (stmt) { return stmt.type === 'ReturnStatement'; });
921
- var finalInsertIndex = newInsertIndex !== -1 ? newInsertIndex : blockStatement.body.length;
922
- // Add all useEffect hooks before the return statement
923
- searchOnlyEffects.reverse().forEach(function (effect) {
924
- blockStatement.body.splice(finalInsertIndex, 0, effect);
727
+ // Add params with useMemo
728
+ var paramsProps = [
729
+ types.objectProperty(types.identifier('page'), types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page'))),
730
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)),
731
+ types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery'))),
732
+ ];
733
+ if (usage.queryColumns.length > 0) {
734
+ paramsProps.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
735
+ }
736
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
737
+ types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
738
+ types.arrayExpression([types.identifier(vars.combinedStateVar)]),
739
+ ]))));
740
+ // Add initialData
741
+ var initialDataCondition = types.logicalExpression('&&', types.binaryExpression('===', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.numericLiteral(1)), types.unaryExpression('!', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')), true));
742
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(initialDataCondition, types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
743
+ // Add key
744
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
745
+ types.templateElement({
746
+ raw: "".concat(usage.dataSourceIdentifier, "-"),
747
+ cooked: "".concat(usage.dataSourceIdentifier, "-"),
748
+ }),
749
+ types.templateElement({ raw: '-', cooked: '-' }),
750
+ types.templateElement({ raw: '', cooked: '' }),
751
+ ], [
752
+ types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')),
753
+ types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')),
754
+ ]))));
755
+ // Add fetchData
756
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
757
+ // Add persistDataDuringLoading
758
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
759
+ }
760
+ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
761
+ var attrs = dp.openingElement.attributes;
762
+ dp.openingElement.attributes = attrs.filter(function (attr) {
763
+ var _a;
764
+ return !['params', 'key', 'initialData', 'fetchData', 'persistDataDuringLoading'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name);
925
765
  });
766
+ // Add params
767
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
768
+ types.arrowFunctionExpression([], types.objectExpression([
769
+ types.objectProperty(types.identifier('page'), types.identifier(vars.pageStateVar)),
770
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)),
771
+ ])),
772
+ types.arrayExpression([types.identifier(vars.pageStateVar)]),
773
+ ]))));
774
+ // Add initialData
775
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
776
+ // Add key
777
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
778
+ types.templateElement({
779
+ raw: "".concat(usage.dataSourceIdentifier, "-page-"),
780
+ cooked: "".concat(usage.dataSourceIdentifier, "-page-"),
781
+ }),
782
+ types.templateElement({ raw: '', cooked: '' }),
783
+ ], [types.identifier(vars.pageStateVar)]))));
784
+ // Add fetchData
785
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
786
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
926
787
  }
927
- function addSearchParamsToDataProvider(dataProviderJSX, config) {
928
- var _a, _b;
929
- if (!dataProviderJSX || !dataProviderJSX.openingElement) {
930
- return;
931
- }
932
- var debouncedSearchQueryVar = config.debouncedSearchQueryVar, queryColumns = config.queryColumns;
933
- // 1. Update params to be wrapped in useMemo
934
- var existingParamsAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
935
- if (existingParamsAttr && ((_a = existingParamsAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
936
- var paramsObj = existingParamsAttr.value.expression;
937
- if (paramsObj.type === 'ObjectExpression') {
938
- // Add query to existing params properties
939
- paramsObj.properties.push(types.objectProperty(types.identifier('query'), types.identifier(debouncedSearchQueryVar)));
940
- // Add queryColumns only if they exist
941
- if (queryColumns.length > 0) {
942
- paramsObj.properties.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(queryColumns.map(function (col) { return types.stringLiteral(col); }))])));
943
- }
944
- // Wrap in useMemo with debouncedSearchQueryVar as dependency
945
- var memoizedParamsValue = types.callExpression(types.identifier('useMemo'), [
946
- types.arrowFunctionExpression([], paramsObj),
947
- types.arrayExpression([types.identifier(debouncedSearchQueryVar)]),
948
- ]);
949
- existingParamsAttr.value.expression = memoizedParamsValue;
950
- }
951
- }
952
- // 2. Update initialData to be conditional on empty search
953
- var existingInitialDataAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
954
- if (existingInitialDataAttr && ((_b = existingInitialDataAttr.value) === null || _b === void 0 ? void 0 : _b.type) === 'JSXExpressionContainer') {
955
- var currentInitialData = existingInitialDataAttr.value.expression;
956
- // Make it conditional: only use initialData if search is empty
957
- existingInitialDataAttr.value.expression = types.conditionalExpression(types.unaryExpression('!', types.identifier(debouncedSearchQueryVar), true), currentInitialData, types.identifier('undefined'));
788
+ function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
789
+ var attrs = dp.openingElement.attributes;
790
+ dp.openingElement.attributes = attrs.filter(function (attr) {
791
+ var _a;
792
+ return !['params', 'key', 'initialData', 'fetchData', 'persistDataDuringLoading'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name);
793
+ });
794
+ // Add params
795
+ var paramsProps = [
796
+ types.objectProperty(types.identifier('query'), types.identifier(vars.debouncedSearchQueryVar)),
797
+ ];
798
+ if (usage.queryColumns.length > 0) {
799
+ paramsProps.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
958
800
  }
959
- // 3. Update key to include search query
960
- var existingKeyAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'key'; });
961
- var keyExpression = types.templateLiteral([
801
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
802
+ types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
803
+ types.arrayExpression([types.identifier(vars.debouncedSearchQueryVar)]),
804
+ ]))));
805
+ // Add initialData
806
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(types.unaryExpression('!', types.identifier(vars.debouncedSearchQueryVar), true), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
807
+ // Add key
808
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
962
809
  types.templateElement({ raw: 'search-', cooked: 'search-' }),
963
810
  types.templateElement({ raw: '', cooked: '' }),
964
- ], [types.identifier(debouncedSearchQueryVar)]);
965
- var keyAttr = types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(keyExpression));
966
- if (existingKeyAttr) {
967
- var index = dataProviderJSX.openingElement.attributes.indexOf(existingKeyAttr);
968
- dataProviderJSX.openingElement.attributes[index] = keyAttr;
969
- }
970
- else {
971
- dataProviderJSX.openingElement.attributes.push(keyAttr);
811
+ ], [types.identifier(vars.debouncedSearchQueryVar)]))));
812
+ // Add fetchData
813
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
814
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
815
+ }
816
+ function updateDataProviderForPlain(dp, vars) {
817
+ var attrs = dp.openingElement.attributes;
818
+ // Remove params and fetchData - plain mappers only use initialData
819
+ dp.openingElement.attributes = attrs.filter(function (attr) { var _a; return !['params', 'fetchData'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name); });
820
+ // Update initialData to use correct prop
821
+ var existingInitialData = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
822
+ if (existingInitialData) {
823
+ existingInitialData.value = types.jsxExpressionContainer(types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true));
972
824
  }
973
825
  }
974
- function addPaginationParamsToDataProvider(dataProviderJSX, info, paginationIndex) {
975
- var _a;
976
- if (!dataProviderJSX || !dataProviderJSX.openingElement) {
826
+ function stabilizeDataProviderWithoutRepeater(dp) {
827
+ var _a, _b, _c;
828
+ var attrs = dp.openingElement.attributes;
829
+ // Find the params attribute
830
+ var paramsAttrIndex = attrs.findIndex(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
831
+ if (paramsAttrIndex === -1) {
977
832
  return;
978
833
  }
979
- var combinedStateVar = info.combinedStateVar;
980
- var paramsProperties;
981
- var dependencies;
982
- if (info.searchEnabled && combinedStateVar) {
983
- // Use combined state for both page and query
984
- paramsProperties = [
985
- types.objectProperty(types.identifier('page'), types.memberExpression(types.identifier(combinedStateVar), types.identifier('page'))),
986
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(info.perPage)),
987
- types.objectProperty(types.identifier('query'), types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery'))),
988
- ];
989
- if (info.queryColumns && info.queryColumns.length > 0) {
990
- paramsProperties.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(info.queryColumns.map(function (col) { return types.stringLiteral(col); }))])));
991
- }
992
- // Single dependency: the combined state object
993
- dependencies = [types.identifier(combinedStateVar)];
994
- }
995
- else {
996
- // Pagination only (no search)
997
- paramsProperties = [
998
- types.objectProperty(types.identifier('page'), types.identifier(info.pageStateVar)),
999
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(info.perPage)),
1000
- ];
1001
- dependencies = [types.identifier(info.pageStateVar)];
1002
- }
1003
- // Wrap params in useMemo to prevent unnecessary refetches
1004
- var memoizedParamsValue = types.callExpression(types.identifier('useMemo'), [
1005
- types.arrowFunctionExpression([], types.objectExpression(paramsProperties)),
1006
- types.arrayExpression(dependencies),
1007
- ]);
1008
- var paramsAttr = types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(memoizedParamsValue));
1009
- var existingParamsAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'params'; });
1010
- if (existingParamsAttr) {
1011
- var index = dataProviderJSX.openingElement.attributes.indexOf(existingParamsAttr);
1012
- dataProviderJSX.openingElement.attributes[index] = paramsAttr;
1013
- }
1014
- else {
1015
- dataProviderJSX.openingElement.attributes.push(paramsAttr);
1016
- }
1017
- var existingInitialDataAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'initialData'; });
1018
- if (existingInitialDataAttr && existingInitialDataAttr.value) {
1019
- // Update initialData to use the paginated prop name
1020
- var paginatedPropName = "".concat(info.dataSourceIdentifier, "_pg_").concat(paginationIndex);
1021
- // If search is enabled, use combined state; otherwise use page state
1022
- var condition = void 0;
1023
- if (info.searchEnabled && combinedStateVar) {
1024
- condition = types.logicalExpression('&&', types.binaryExpression('===', types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')), types.numericLiteral(1)), types.unaryExpression('!', types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery')), true));
1025
- }
1026
- else {
1027
- condition = types.binaryExpression('===', types.identifier(info.pageStateVar), types.numericLiteral(1));
1028
- }
1029
- existingInitialDataAttr.value.expression = types.conditionalExpression(condition, types.optionalMemberExpression(types.identifier('props'), types.identifier(paginatedPropName), false, true), types.identifier('undefined'));
1030
- }
1031
- var existingKeyAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'key'; });
1032
- // Include page and search in key to trigger refetch when they change
1033
- var keyExpression;
1034
- if (info.searchEnabled && combinedStateVar) {
1035
- keyExpression = types.templateLiteral([
1036
- types.templateElement({
1037
- raw: "".concat(info.dataSourceIdentifier, "-page-"),
1038
- cooked: "".concat(info.dataSourceIdentifier, "-page-"),
1039
- }),
1040
- types.templateElement({ raw: '-search-', cooked: '-search-' }),
1041
- types.templateElement({ raw: '', cooked: '' }),
1042
- ], [
1043
- types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')),
1044
- types.memberExpression(types.identifier(combinedStateVar), types.identifier('debouncedQuery')),
1045
- ]);
1046
- }
1047
- else {
1048
- keyExpression = types.templateLiteral([
1049
- types.templateElement({
1050
- raw: "".concat(info.dataSourceIdentifier, "-"),
1051
- cooked: "".concat(info.dataSourceIdentifier, "-"),
1052
- }),
1053
- types.templateElement({ raw: '', cooked: '' }),
1054
- ], [types.identifier(info.pageStateVar)]);
1055
- }
1056
- var keyAttr = types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(keyExpression));
1057
- if (existingKeyAttr) {
1058
- var index = dataProviderJSX.openingElement.attributes.indexOf(existingKeyAttr);
1059
- dataProviderJSX.openingElement.attributes[index] = keyAttr;
834
+ var paramsAttr = attrs[paramsAttrIndex];
835
+ // Check if params is already wrapped in useMemo
836
+ if (((_a = paramsAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer' &&
837
+ paramsAttr.value.expression.type === 'CallExpression' &&
838
+ ((_b = paramsAttr.value.expression.callee) === null || _b === void 0 ? void 0 : _b.name) === 'useMemo') {
839
+ return;
1060
840
  }
1061
- else {
1062
- dataProviderJSX.openingElement.attributes.push(keyAttr);
841
+ // Get the current params value expression
842
+ var paramsExpression = null;
843
+ if (((_c = paramsAttr.value) === null || _c === void 0 ? void 0 : _c.type) === 'JSXExpressionContainer') {
844
+ paramsExpression = paramsAttr.value.expression;
1063
845
  }
1064
- // For pagination, always create a fresh fetchData that calls the API route
1065
- // Get the resource definition to build the API URL
1066
- var resourceDefAttr = dataProviderJSX.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'resourceDefinition'; });
1067
- if (resourceDefAttr && ((_a = resourceDefAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
1068
- var resourceDef = resourceDefAttr.value.expression;
1069
- if (resourceDef.type === 'ObjectExpression') {
1070
- var dataSourceIdProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceId'; });
1071
- var tableNameProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'tableName'; });
1072
- var dataSourceTypeProp = resourceDef.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.value === 'dataSourceType'; });
1073
- if (dataSourceIdProp && tableNameProp && dataSourceTypeProp) {
1074
- var dataSourceId = dataSourceIdProp.value.value;
1075
- var tableName = tableNameProp.value.value;
1076
- var dataSourceType = dataSourceTypeProp.value.value;
1077
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
1078
- // Create fetchData attribute with proper fetch chain wrapped in useCallback
1079
- var fetchDataValue = types.callExpression(types.identifier('useCallback'), [
1080
- types.arrowFunctionExpression([types.identifier('params')], types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
1081
- types.templateLiteral([
1082
- types.templateElement({
1083
- raw: "/api/".concat(fileName, "?"),
1084
- cooked: "/api/".concat(fileName, "?"),
1085
- }),
1086
- types.templateElement({ raw: '', cooked: '' }),
1087
- ], [
1088
- types.newExpression(types.identifier('URLSearchParams'), [
1089
- types.identifier('params'),
1090
- ]),
1091
- ]),
1092
- types.objectExpression([
1093
- types.objectProperty(types.identifier('headers'), types.objectExpression([
1094
- types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
1095
- ])),
1096
- ]),
1097
- ]), types.identifier('then')), [
1098
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
1099
- ]), types.identifier('then')), [
1100
- types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true)),
1101
- ])),
1102
- types.arrayExpression([]),
1103
- ]);
1104
- var newFetchDataAttr = types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(fetchDataValue));
1105
- // Remove existing fetchData attribute if present
1106
- var existingFetchDataIndex = dataProviderJSX.openingElement.attributes.findIndex(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'fetchData'; });
1107
- if (existingFetchDataIndex !== -1) {
1108
- dataProviderJSX.openingElement.attributes[existingFetchDataIndex] = newFetchDataAttr;
1109
- }
1110
- else {
1111
- dataProviderJSX.openingElement.attributes.push(newFetchDataAttr);
1112
- }
1113
- }
1114
- }
846
+ if (!paramsExpression) {
847
+ return;
1115
848
  }
849
+ // Wrap params in useMemo with empty dependencies array
850
+ // This ensures the object reference stays stable across re-renders
851
+ var memoizedParams = types.callExpression(types.identifier('useMemo'), [
852
+ types.arrowFunctionExpression([], paramsExpression),
853
+ types.arrayExpression([]),
854
+ ]);
855
+ // Replace the params attribute
856
+ attrs[paramsAttrIndex] = types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(memoizedParams));
1116
857
  }
1117
- function findChildWithClass(node, classSubstring) {
1118
- var _a;
1119
- if (!node) {
1120
- return null;
1121
- }
1122
- if (node.type === 'JSXElement') {
1123
- var className = getClassName(((_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) || []);
1124
- if (className && className.includes(classSubstring)) {
1125
- return className;
1126
- }
1127
- }
1128
- if (node.children) {
1129
- for (var _i = 0, _b = node.children; _i < _b.length; _i++) {
1130
- var child = _b[_i];
1131
- var found = findChildWithClass(child, classSubstring);
1132
- if (found) {
1133
- return found;
1134
- }
1135
- }
1136
- }
1137
- if (typeof node === 'object') {
1138
- for (var _c = 0, _d = Object.values(node); _c < _d.length; _c++) {
1139
- var value = _d[_c];
1140
- if (Array.isArray(value)) {
1141
- for (var _e = 0, value_1 = value; _e < value_1.length; _e++) {
1142
- var item = value_1[_e];
1143
- var found = findChildWithClass(item, classSubstring);
1144
- if (found) {
1145
- return found;
1146
- }
1147
- }
1148
- }
1149
- else if (typeof value === 'object') {
1150
- var found = findChildWithClass(value, classSubstring);
1151
- if (found) {
1152
- return found;
1153
- }
1154
- }
1155
- }
1156
- }
1157
- return null;
858
+ function createFetchDataAttribute(fileName) {
859
+ return types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(types.callExpression(types.identifier('useCallback'), [
860
+ types.arrowFunctionExpression([types.identifier('params')], types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
861
+ types.templateLiteral([
862
+ types.templateElement({
863
+ raw: "/api/".concat(fileName, "?"),
864
+ cooked: "/api/".concat(fileName, "?"),
865
+ }),
866
+ types.templateElement({ raw: '', cooked: '' }),
867
+ ], [
868
+ types.newExpression(types.identifier('URLSearchParams'), [
869
+ types.identifier('params'),
870
+ ]),
871
+ ]),
872
+ types.objectExpression([
873
+ types.objectProperty(types.identifier('headers'), types.objectExpression([
874
+ types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
875
+ ])),
876
+ ]),
877
+ ]), types.identifier('then')), [
878
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
879
+ ]), types.identifier('then')), [
880
+ types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true)),
881
+ ])),
882
+ types.arrayExpression([]),
883
+ ])));
1158
884
  }
1159
- function modifyPaginationButtons(blockStatement, detectedPaginations, paginationInfos) {
1160
- var modifiedButtons = new Set();
1161
- var modifyNode = function (node) {
885
+ function wireSearchInput(inputNode, vars) {
886
+ // Remove existing onChange and value
887
+ inputNode.openingElement.attributes = inputNode.openingElement.attributes.filter(function (attr) { var _a; return !['onChange', 'value'].includes((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name); });
888
+ // Add onChange
889
+ inputNode.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onChange'), types.jsxExpressionContainer(types.arrowFunctionExpression([types.identifier('e')], types.callExpression(types.identifier(vars.setSearchQueryVar), [
890
+ types.memberExpression(types.memberExpression(types.identifier('e'), types.identifier('target')), types.identifier('value')),
891
+ ])))));
892
+ // Add value
893
+ inputNode.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('value'), types.jsxExpressionContainer(types.identifier(vars.searchQueryVar))));
894
+ }
895
+ function wirePaginationButtons(paginationNode, usage, vars) {
896
+ // Find prev and next buttons
897
+ var findButton = function (node, direction) {
898
+ var _a, _b, _c, _d, _e;
1162
899
  if (!node) {
1163
- return;
900
+ return null;
1164
901
  }
1165
902
  if (node.type === 'JSXElement') {
1166
- var openingElement = node.openingElement;
1167
- if (openingElement && openingElement.name && openingElement.name.type === 'JSXIdentifier') {
1168
- var className = getClassName(openingElement.attributes);
1169
- if (className && !modifiedButtons.has(node)) {
1170
- for (var index = 0; index < detectedPaginations.length; index++) {
1171
- var detected = detectedPaginations[index];
1172
- var info = paginationInfos[index];
1173
- if (!info) {
1174
- continue;
1175
- }
1176
- if (className === detected.prevButtonClass) {
1177
- convertToButton(node, info, 'prev');
1178
- modifiedButtons.add(node);
1179
- break;
1180
- }
1181
- else if (className === detected.nextButtonClass) {
1182
- convertToButton(node, info, 'next');
1183
- modifiedButtons.add(node);
1184
- break;
1185
- }
1186
- }
1187
- }
903
+ var classAttr = (_b = (_a = node.openingElement) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
904
+ var className = ((_c = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _c === void 0 ? void 0 : _c.value) || ((_e = (_d = classAttr === null || classAttr === void 0 ? void 0 : classAttr.value) === null || _d === void 0 ? void 0 : _d.expression) === null || _e === void 0 ? void 0 : _e.value) || '';
905
+ if (className.includes(direction)) {
906
+ return node;
1188
907
  }
1189
908
  }
1190
- if (typeof node === 'object') {
1191
- Object.values(node).forEach(function (value) {
1192
- if (Array.isArray(value)) {
1193
- value.forEach(function (item) { return modifyNode(item); });
1194
- }
1195
- else if (typeof value === 'object') {
1196
- modifyNode(value);
909
+ if (node.children && Array.isArray(node.children)) {
910
+ for (var _i = 0, _f = node.children; _i < _f.length; _i++) {
911
+ var c = _f[_i];
912
+ var found = findButton(c, direction);
913
+ if (found) {
914
+ return found;
1197
915
  }
1198
- });
916
+ }
1199
917
  }
918
+ return null;
1200
919
  };
1201
- modifyNode(blockStatement);
1202
- }
1203
- function modifySearchInputs(blockStatement, detectedPaginations, paginationInfos) {
1204
- var modifiedInputs = new Set();
1205
- var modifyNode = function (node) {
1206
- if (!node) {
1207
- return;
920
+ var prevButton = findButton(paginationNode, 'previous');
921
+ var nextButton = findButton(paginationNode, 'next');
922
+ var isCombinedState = usage.category === 'paginated+search';
923
+ if (prevButton) {
924
+ // Change to button element
925
+ prevButton.openingElement.name.name = 'button';
926
+ if (prevButton.closingElement) {
927
+ prevButton.closingElement.name.name = 'button';
1208
928
  }
1209
- if (node.type === 'JSXElement') {
1210
- var openingElement = node.openingElement;
1211
- if (openingElement && openingElement.name && openingElement.name.type === 'JSXIdentifier') {
1212
- var className = getClassName(openingElement.attributes);
1213
- if (className && !modifiedInputs.has(node)) {
1214
- for (var index = 0; index < detectedPaginations.length; index++) {
1215
- var detected = detectedPaginations[index];
1216
- var info = paginationInfos[index];
1217
- if (!info || !info.searchEnabled) {
1218
- continue;
1219
- }
1220
- if (className === detected.searchInputClass) {
1221
- addSearchInputHandlers(node, info);
1222
- modifiedInputs.add(node);
1223
- break;
1224
- }
1225
- }
1226
- }
1227
- }
1228
- }
1229
- if (typeof node === 'object') {
1230
- Object.values(node).forEach(function (value) {
1231
- if (Array.isArray(value)) {
1232
- value.forEach(function (item) { return modifyNode(item); });
1233
- }
1234
- else if (typeof value === 'object') {
1235
- modifyNode(value);
1236
- }
1237
- });
929
+ // Add type="button"
930
+ var hasType = prevButton.openingElement.attributes.some(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) === 'type'; });
931
+ if (!hasType) {
932
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('type'), types.stringLiteral('button')));
1238
933
  }
1239
- };
1240
- modifyNode(blockStatement);
1241
- }
1242
- function addSearchInputHandlers(jsxElement, info) {
1243
- if (!info.searchQueryVar || !info.setSearchQueryVar) {
1244
- return;
1245
- }
1246
- var openingElement = jsxElement.openingElement;
1247
- removeAttribute(openingElement.attributes, 'onChange');
1248
- removeAttribute(openingElement.attributes, 'value');
1249
- var onChangeHandler = types.arrowFunctionExpression([types.identifier('e')], types.callExpression(types.identifier(info.setSearchQueryVar), [
1250
- types.memberExpression(types.memberExpression(types.identifier('e'), types.identifier('target')), types.identifier('value')),
1251
- ]));
1252
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onChange'), types.jsxExpressionContainer(onChangeHandler)));
1253
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('value'), types.jsxExpressionContainer(types.identifier(info.searchQueryVar))));
1254
- }
1255
- function convertToButton(jsxElement, info, buttonType) {
1256
- var openingElement = jsxElement.openingElement;
1257
- if (openingElement.name.type === 'JSXIdentifier') {
1258
- openingElement.name.name = 'button';
1259
- }
1260
- if (jsxElement.closingElement && jsxElement.closingElement.name.type === 'JSXIdentifier') {
1261
- jsxElement.closingElement.name.name = 'button';
1262
- }
1263
- removeAttribute(openingElement.attributes, 'onClick');
1264
- removeAttribute(openingElement.attributes, 'disabled');
1265
- removeAttribute(openingElement.attributes, 'type');
1266
- var combinedStateVar = info.combinedStateVar;
1267
- var setCombinedStateVar = info.setCombinedStateVar;
1268
- var onClickHandler;
1269
- if (info.searchEnabled && combinedStateVar && setCombinedStateVar) {
1270
- // Use combined state: update only the page property
1271
- onClickHandler =
1272
- buttonType === 'prev'
1273
- ? types.arrowFunctionExpression([], types.callExpression(types.identifier(setCombinedStateVar), [
1274
- types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
1275
- types.spreadElement(types.identifier('state')),
1276
- types.objectProperty(types.identifier('page'), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
1277
- types.numericLiteral(1),
1278
- types.binaryExpression('-', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1)),
1279
- ])),
1280
- ])),
1281
- ]))
1282
- : types.arrowFunctionExpression([], types.callExpression(types.identifier(setCombinedStateVar), [
1283
- types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
1284
- types.spreadElement(types.identifier('state')),
1285
- types.objectProperty(types.identifier('page'), types.binaryExpression('+', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1))),
1286
- ])),
1287
- ]));
1288
- }
1289
- else {
1290
- // Regular pagination (no search)
1291
- onClickHandler =
1292
- buttonType === 'prev'
1293
- ? types.arrowFunctionExpression([], types.callExpression(types.identifier(info.setPageStateVar), [
1294
- types.arrowFunctionExpression([types.identifier('p')], types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
934
+ // Add onClick
935
+ prevButton.openingElement.attributes = prevButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'onClick'; });
936
+ if (isCombinedState) {
937
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setCombinedStateVar), [
938
+ types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
939
+ types.spreadElement(types.identifier('state')),
940
+ types.objectProperty(types.identifier('page'), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
1295
941
  types.numericLiteral(1),
1296
- types.binaryExpression('-', types.identifier('p'), types.numericLiteral(1)),
942
+ types.binaryExpression('-', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1)),
1297
943
  ])),
1298
- ]))
1299
- : types.arrowFunctionExpression([], types.callExpression(types.identifier(info.setPageStateVar), [
1300
- types.arrowFunctionExpression([types.identifier('p')], types.binaryExpression('+', types.identifier('p'), types.numericLiteral(1))),
1301
- ]));
1302
- }
1303
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(onClickHandler)));
1304
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('type'), types.stringLiteral('button')));
1305
- // Add disabled attribute with simple page number checks
1306
- var maxPagesStateVar = info.maxPagesStateVar;
1307
- var disabledExpr;
1308
- if (info.searchEnabled && combinedStateVar) {
1309
- disabledExpr =
1310
- buttonType === 'prev'
1311
- ? types.binaryExpression('<=', types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')), types.numericLiteral(1))
1312
- : types.binaryExpression('>=', types.memberExpression(types.identifier(combinedStateVar), types.identifier('page')), types.identifier(maxPagesStateVar));
1313
- }
1314
- else {
1315
- disabledExpr =
1316
- buttonType === 'prev'
1317
- ? types.binaryExpression('<=', types.identifier(info.pageStateVar), types.numericLiteral(1))
1318
- : types.binaryExpression('>=', types.identifier(info.pageStateVar), types.identifier(maxPagesStateVar));
944
+ ])),
945
+ ])))));
946
+ // Add disabled
947
+ prevButton.openingElement.attributes = prevButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
948
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('<=', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.numericLiteral(1)))));
949
+ }
950
+ else {
951
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setPageStateVar), [
952
+ types.arrowFunctionExpression([types.identifier('page')], types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('max')), [
953
+ types.numericLiteral(1),
954
+ types.binaryExpression('-', types.identifier('page'), types.numericLiteral(1)),
955
+ ])),
956
+ ])))));
957
+ prevButton.openingElement.attributes = prevButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
958
+ prevButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('<=', types.identifier(vars.pageStateVar), types.numericLiteral(1)))));
959
+ }
1319
960
  }
1320
- openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(disabledExpr)));
1321
- }
1322
- function getClassName(attributes) {
1323
- var classNameAttr = attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'className'; });
1324
- if (classNameAttr && classNameAttr.value && classNameAttr.value.type === 'StringLiteral') {
1325
- return classNameAttr.value.value;
961
+ if (nextButton) {
962
+ nextButton.openingElement.name.name = 'button';
963
+ if (nextButton.closingElement) {
964
+ nextButton.closingElement.name.name = 'button';
965
+ }
966
+ var hasType = nextButton.openingElement.attributes.some(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) === 'type'; });
967
+ if (!hasType) {
968
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('type'), types.stringLiteral('button')));
969
+ }
970
+ nextButton.openingElement.attributes = nextButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'onClick'; });
971
+ if (isCombinedState) {
972
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setCombinedStateVar), [
973
+ types.arrowFunctionExpression([types.identifier('state')], types.objectExpression([
974
+ types.spreadElement(types.identifier('state')),
975
+ types.objectProperty(types.identifier('page'), types.binaryExpression('+', types.memberExpression(types.identifier('state'), types.identifier('page')), types.numericLiteral(1))),
976
+ ])),
977
+ ])))));
978
+ nextButton.openingElement.attributes = nextButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
979
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('>=', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.identifier(vars.maxPagesStateVar)))));
980
+ }
981
+ else {
982
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('onClick'), types.jsxExpressionContainer(types.arrowFunctionExpression([], types.callExpression(types.identifier(vars.setPageStateVar), [
983
+ types.arrowFunctionExpression([types.identifier('page')], types.binaryExpression('+', types.identifier('page'), types.numericLiteral(1))),
984
+ ])))));
985
+ nextButton.openingElement.attributes = nextButton.openingElement.attributes.filter(function (a) { var _a; return ((_a = a.name) === null || _a === void 0 ? void 0 : _a.name) !== 'disabled'; });
986
+ nextButton.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('disabled'), types.jsxExpressionContainer(types.binaryExpression('>=', types.identifier(vars.pageStateVar), types.identifier(vars.maxPagesStateVar)))));
987
+ }
1326
988
  }
1327
- return null;
1328
989
  }
1329
- function removeAttribute(attrs, attributeName) {
1330
- var index = attrs.findIndex(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === attributeName; });
1331
- if (index !== -1) {
1332
- attrs.splice(index, 1);
990
+ function ensureAPIRouteExists(extractedResources, usage) {
991
+ // Generate file name for the API route
992
+ var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
993
+ // Check if the utils data source file exists - if so, create API routes that re-export from it
994
+ if (extractedResources["utils/".concat(fileName)]) {
995
+ // Create main data API route if not exists
996
+ if (!extractedResources["api/".concat(fileName)]) {
997
+ var apiRouteCode = "import dataSourceModule from '../../utils/data-sources/".concat(fileName, "'\n\nexport default dataSourceModule.handler\n");
998
+ extractedResources["api/".concat(fileName)] = {
999
+ fileName: fileName,
1000
+ fileType: FileType.JS,
1001
+ path: ['pages', 'api'],
1002
+ content: apiRouteCode,
1003
+ };
1004
+ }
1005
+ // Create count API route if not exists (needed for paginated+search cases)
1006
+ var countFileName = "".concat(fileName, "-count");
1007
+ if (!extractedResources["api/".concat(countFileName)]) {
1008
+ var countApiRouteCode = "import dataSourceModule from '../../utils/data-sources/".concat(fileName, "'\n\nexport default dataSourceModule.getCount\n");
1009
+ extractedResources["api/".concat(countFileName)] = {
1010
+ fileName: countFileName,
1011
+ fileType: FileType.JS,
1012
+ path: ['pages', 'api'],
1013
+ content: countApiRouteCode,
1014
+ };
1015
+ }
1333
1016
  }
1334
1017
  }
1335
- function modifyGetStaticPropsForPagination(chunks, paginationInfos) {
1018
+ function updateGetStaticProps(chunks, registry) {
1336
1019
  var _a;
1337
- var getStaticPropsChunk = chunks.find(function (chunk) { return chunk.name === 'getStaticProps'; });
1338
- if (!getStaticPropsChunk || getStaticPropsChunk.type !== 'ast') {
1020
+ var getStaticPropsChunk = chunks.find(function (c) { return c.name === 'getStaticProps'; });
1021
+ if (!getStaticPropsChunk || getStaticPropsChunk.type !== ChunkType.AST) {
1339
1022
  return;
1340
1023
  }
1341
- var exportDeclaration = getStaticPropsChunk.content;
1342
- if (!exportDeclaration || exportDeclaration.type !== 'ExportNamedDeclaration') {
1024
+ var content = getStaticPropsChunk.content;
1025
+ if (!content.declaration || content.declaration.type !== 'FunctionDeclaration') {
1343
1026
  return;
1344
1027
  }
1345
- var functionDeclaration = exportDeclaration.declaration;
1346
- if (!functionDeclaration || functionDeclaration.type !== 'FunctionDeclaration') {
1028
+ var funcBody = content.declaration.body;
1029
+ var tryStmt = funcBody.body.find(function (s) { return s.type === 'TryStatement'; });
1030
+ if (!tryStmt) {
1347
1031
  return;
1348
1032
  }
1349
- // Find Promise.all and add NEW fetchData calls for each paginated DataProvider
1350
- var functionBody = functionDeclaration.body.body;
1351
- var tryBlock = functionBody.find(function (stmt) { return stmt.type === 'TryStatement'; });
1352
- if (!tryBlock) {
1353
- return;
1354
- }
1355
- var tryBody = tryBlock.block.body;
1356
- // Find the Promise.all statement
1357
- var promiseAllStmt = tryBody.find(function (stmt) {
1033
+ var tryBlock = tryStmt.block;
1034
+ // Find existing Promise.all
1035
+ var promiseAllDecl = tryBlock.body.find(function (s) {
1358
1036
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
1359
- return stmt.type === 'VariableDeclaration' &&
1360
- ((_c = (_b = (_a = stmt.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.init) === null || _c === void 0 ? void 0 : _c.type) === 'AwaitExpression' &&
1361
- ((_g = (_f = (_e = (_d = stmt.declarations) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.init) === null || _f === void 0 ? void 0 : _f.argument) === null || _g === void 0 ? void 0 : _g.type) === 'CallExpression' &&
1362
- ((_m = (_l = (_k = (_j = (_h = stmt.declarations) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.init) === null || _k === void 0 ? void 0 : _k.argument) === null || _l === void 0 ? void 0 : _l.callee) === null || _m === void 0 ? void 0 : _m.type) === 'MemberExpression' &&
1363
- ((_t = (_s = (_r = (_q = (_p = (_o = stmt.declarations) === null || _o === void 0 ? void 0 : _o[0]) === null || _p === void 0 ? void 0 : _p.init) === null || _q === void 0 ? void 0 : _q.argument) === null || _r === void 0 ? void 0 : _r.callee) === null || _s === void 0 ? void 0 : _s.property) === null || _t === void 0 ? void 0 : _t.name) === 'all';
1037
+ return s.type === 'VariableDeclaration' &&
1038
+ ((_c = (_b = (_a = s.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.init) === null || _c === void 0 ? void 0 : _c.type) === 'AwaitExpression' &&
1039
+ ((_g = (_f = (_e = (_d = s.declarations) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.init) === null || _f === void 0 ? void 0 : _f.argument) === null || _g === void 0 ? void 0 : _g.type) === 'CallExpression' &&
1040
+ ((_m = (_l = (_k = (_j = (_h = s.declarations) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.init) === null || _k === void 0 ? void 0 : _k.argument) === null || _l === void 0 ? void 0 : _l.callee) === null || _m === void 0 ? void 0 : _m.type) === 'MemberExpression' &&
1041
+ ((_t = (_s = (_r = (_q = (_p = (_o = s.declarations) === null || _o === void 0 ? void 0 : _o[0]) === null || _p === void 0 ? void 0 : _p.init) === null || _q === void 0 ? void 0 : _q.argument) === null || _r === void 0 ? void 0 : _r.callee) === null || _s === void 0 ? void 0 : _s.object) === null || _t === void 0 ? void 0 : _t.name) === 'Promise';
1364
1042
  });
1365
- if (!promiseAllStmt) {
1043
+ if (!promiseAllDecl) {
1366
1044
  return;
1367
1045
  }
1368
- var awaitExpr = promiseAllStmt.declarations[0].init;
1046
+ var declarator = promiseAllDecl.declarations[0];
1047
+ var awaitExpr = declarator.init;
1369
1048
  var promiseAllCall = awaitExpr.argument;
1370
- var promiseArray = promiseAllCall.arguments[0];
1371
- var destructuringPattern = promiseAllStmt.declarations[0].id;
1372
- // Map import names to data source identifiers from existing fetchData calls
1373
- // Also track which indices to remove (non-paginated calls that will be replaced)
1374
- var importToDataSource = new Map();
1375
- var indicesToRemove = [];
1376
- promiseArray.elements.forEach(function (element, index) {
1377
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1378
- if (element && element.type === 'CallExpression') {
1379
- var fetchCallExpr = element;
1380
- // If wrapped in .catch(), unwrap it
1381
- if (((_a = element.callee) === null || _a === void 0 ? void 0 : _a.type) === 'MemberExpression' &&
1382
- ((_c = (_b = element.callee) === null || _b === void 0 ? void 0 : _b.property) === null || _c === void 0 ? void 0 : _c.name) === 'catch' &&
1383
- ((_e = (_d = element.callee) === null || _d === void 0 ? void 0 : _d.object) === null || _e === void 0 ? void 0 : _e.type) === 'CallExpression') {
1384
- fetchCallExpr = element.callee.object;
1385
- }
1386
- // Now find the .fetchData() call
1387
- if (((_f = fetchCallExpr.callee) === null || _f === void 0 ? void 0 : _f.type) === 'MemberExpression' &&
1388
- ((_h = (_g = fetchCallExpr.callee) === null || _g === void 0 ? void 0 : _g.property) === null || _h === void 0 ? void 0 : _h.name) === 'fetchData' &&
1389
- ((_k = (_j = fetchCallExpr.callee) === null || _j === void 0 ? void 0 : _j.object) === null || _k === void 0 ? void 0 : _k.type) === 'Identifier') {
1390
- var importName = fetchCallExpr.callee.object.name;
1391
- var dataSourceVar_1 = destructuringPattern.elements[index].name;
1392
- // Check if this fetchData call has page/perPage params
1393
- var params = fetchCallExpr.arguments[0];
1394
- var hasPageParam = params &&
1395
- params.type === 'ObjectExpression' &&
1396
- params.properties.some(function (prop) {
1397
- return prop.type === 'ObjectProperty' &&
1398
- (prop.key.name === 'page' || prop.key.name === 'perPage');
1399
- });
1400
- // If this is a data source that will be paginated but this call has NO pagination params,
1401
- // mark it for removal
1402
- if (!hasPageParam &&
1403
- paginationInfos.some(function (info) { return info.dataSourceIdentifier === dataSourceVar_1; })) {
1404
- indicesToRemove.push(index);
1405
- }
1406
- importToDataSource.set(importName, dataSourceVar_1);
1407
- }
1049
+ var fetchesArray = promiseAllCall.arguments[0];
1050
+ // Find return statement
1051
+ var returnStmt = tryBlock.body.find(function (s) { return s.type === 'ReturnStatement'; });
1052
+ if (!returnStmt || ((_a = returnStmt.argument) === null || _a === void 0 ? void 0 : _a.type) !== 'ObjectExpression') {
1053
+ return;
1054
+ }
1055
+ var returnObj = returnStmt.argument;
1056
+ var propsProperty = returnObj.properties.find(function (p) { return p.type === 'ObjectProperty' && p.key.type === 'Identifier' && p.key.name === 'props'; });
1057
+ if (!propsProperty || propsProperty.value.type !== 'ObjectExpression') {
1058
+ return;
1059
+ }
1060
+ var propsObj = propsProperty.value;
1061
+ var arrayPattern = declarator.id;
1062
+ // Track unique data sources for count fetching
1063
+ var dataSourcesNeedingCount = new Set();
1064
+ registry.usages.forEach(function (usage) {
1065
+ var vars = getStateVarsForUsage(usage);
1066
+ var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
1067
+ // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
1068
+ var fetcherImportName = StringUtils.dashCaseToCamelCase(fileName);
1069
+ // Add fetch call
1070
+ var fetchParams = [];
1071
+ if (usage.paginated) {
1072
+ // For paginated array mappers, add page and perPage
1073
+ fetchParams.push(types.objectProperty(types.identifier('page'), types.numericLiteral(1)));
1074
+ fetchParams.push(types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)));
1408
1075
  }
1409
- });
1410
- // Remove non-paginated fetchData calls in reverse order to preserve indices
1411
- indicesToRemove.reverse().forEach(function (index) {
1412
- var _a, _b;
1413
- // Get the prop name BEFORE removing it
1414
- var propToRemove = (_a = destructuringPattern.elements[index]) === null || _a === void 0 ? void 0 : _a.name;
1415
- promiseArray.elements.splice(index, 1);
1416
- destructuringPattern.elements.splice(index, 1);
1417
- // Also remove from props in return statement
1418
- if (propToRemove) {
1419
- var foundReturnStmt = tryBody.find(function (stmt) { return stmt.type === 'ReturnStatement'; });
1420
- if (foundReturnStmt && ((_b = foundReturnStmt.argument) === null || _b === void 0 ? void 0 : _b.type) === 'ObjectExpression') {
1421
- var propsProperty = foundReturnStmt.argument.properties.find(function (prop) {
1422
- return prop.type === 'ObjectProperty' && prop.key.name === 'props';
1423
- });
1424
- if (propsProperty && propsProperty.value.type === 'ObjectExpression') {
1425
- var propsObject = propsProperty.value;
1426
- var propIndex = propsObject.properties.findIndex(function (prop) {
1427
- return prop.type === 'ObjectProperty' && prop.key.name === propToRemove;
1428
- });
1429
- if (propIndex !== -1) {
1430
- propsObject.properties.splice(propIndex, 1);
1431
- }
1432
- }
1433
- }
1076
+ else if (usage.perPage > 0) {
1077
+ // For non-paginated array mappers with a limit, add the limit as perPage
1078
+ // This ensures the initial data fetch respects the limit from the UIDL
1079
+ fetchParams.push(types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)));
1434
1080
  }
1435
- });
1436
- // Add NEW fetchData calls for each paginated DataProvider
1437
- paginationInfos.forEach(function (info, index) {
1438
- var _a, _b;
1439
- // Try exact match first, then case-insensitive match
1440
- var importName = (_a = Array.from(importToDataSource.entries()).find(function (_a) {
1441
- var _ = _a[0], dataSourceVar = _a[1];
1442
- return dataSourceVar === info.dataSourceIdentifier;
1443
- })) === null || _a === void 0 ? void 0 : _a[0];
1444
- if (!importName) {
1445
- // Try case-insensitive match
1446
- var normalizedIdentifier_1 = info.dataSourceIdentifier.toLowerCase().replace(/[_-]/g, '');
1447
- importName = (_b = Array.from(importToDataSource.entries()).find(function (_a) {
1448
- var _ = _a[0], dataSourceVar = _a[1];
1449
- return dataSourceVar.toLowerCase().replace(/[_-]/g, '') === normalizedIdentifier_1;
1450
- })) === null || _b === void 0 ? void 0 : _b[0];
1081
+ if (usage.queryColumns.length > 0) {
1082
+ fetchParams.push(types.objectProperty(types.identifier('queryColumns'), types.callExpression(types.memberExpression(types.identifier('JSON'), types.identifier('stringify')), [types.arrayExpression(usage.queryColumns.map(function (c) { return types.stringLiteral(c); }))])));
1451
1083
  }
1452
- if (importName) {
1453
- var paginatedVarName = "".concat(info.dataSourceIdentifier, "_pg_").concat(index);
1454
- var fetchParams = [
1455
- types.objectProperty(types.identifier('page'), types.numericLiteral(1)),
1456
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(info.perPage)),
1457
- ];
1458
- // Add queryColumns if they exist
1459
- if (info.queryColumns && info.queryColumns.length > 0) {
1460
- fetchParams.push(types.objectProperty(types.identifier('queryColumns'), types.arrayExpression(info.queryColumns.map(function (col) { return types.stringLiteral(col); }))));
1461
- }
1462
- // Create new fetchData call with pagination params
1463
- var newFetchDataCall = types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(importName), types.identifier('fetchData')), [types.objectExpression(fetchParams)]), types.identifier('catch')), [
1084
+ // Check if this fetch already exists
1085
+ var existingFetchIndex = arrayPattern.elements.findIndex(function (el) { return (el === null || el === void 0 ? void 0 : el.type) === 'Identifier' && el.name === vars.propsPrefix; });
1086
+ if (existingFetchIndex === -1) {
1087
+ arrayPattern.elements.push(types.identifier(vars.propsPrefix));
1088
+ fetchesArray.elements.push(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchData')), [types.objectExpression(fetchParams)]), types.identifier('catch')), [
1464
1089
  types.arrowFunctionExpression([types.identifier('error')], types.blockStatement([
1465
1090
  types.expressionStatement(types.callExpression(types.memberExpression(types.identifier('console'), types.identifier('error')), [
1466
- types.stringLiteral("Error fetching ".concat(paginatedVarName, ":")),
1091
+ types.stringLiteral("Error fetching ".concat(vars.propsPrefix, ":")),
1467
1092
  types.identifier('error'),
1468
1093
  ])),
1469
1094
  types.returnStatement(types.arrayExpression([])),
1470
1095
  ])),
1471
- ]);
1472
- promiseArray.elements.push(newFetchDataCall);
1473
- destructuringPattern.elements.push(types.identifier(paginatedVarName));
1096
+ ]));
1097
+ // Add to props
1098
+ propsObj.properties.push(types.objectProperty(types.identifier(vars.propsPrefix), types.identifier(vars.propsPrefix)));
1474
1099
  }
1475
- });
1476
- // Add fetchCount calls for paginated data sources (deduplicated by data source)
1477
- // Deduplicate by data source identifier
1478
- var uniqueDataSources = new Set(paginationInfos.map(function (info) { return info.dataSourceIdentifier; }));
1479
- var addedCountFetches = new Set();
1480
- uniqueDataSources.forEach(function (dataSourceId) {
1481
- var _a, _b;
1482
- var importName = (_a = Array.from(importToDataSource.entries()).find(function (_a) {
1483
- var _ = _a[0], dataSourceVar = _a[1];
1484
- return dataSourceVar === dataSourceId;
1485
- })) === null || _a === void 0 ? void 0 : _a[0];
1486
- if (!importName) {
1487
- // Try case-insensitive match
1488
- var normalizedIdentifier_2 = dataSourceId.toLowerCase().replace(/[_-]/g, '');
1489
- importName = (_b = Array.from(importToDataSource.entries()).find(function (_a) {
1490
- var _ = _a[0], dataSourceVar = _a[1];
1491
- return dataSourceVar.toLowerCase().replace(/[_-]/g, '') === normalizedIdentifier_2;
1492
- })) === null || _b === void 0 ? void 0 : _b[0];
1100
+ // Track for count fetching
1101
+ if (usage.paginated) {
1102
+ dataSourcesNeedingCount.add("".concat(usage.resourceDefinition.dataSourceType, ":").concat(usage.resourceDefinition.tableName, ":").concat(usage.resourceDefinition.dataSourceId));
1493
1103
  }
1494
- if (importName && !addedCountFetches.has(dataSourceId)) {
1495
- var fetchCountCall = types.callExpression(types.memberExpression(types.identifier(importName), types.identifier('fetchCount')), []);
1496
- promiseArray.elements.push(fetchCountCall);
1497
- destructuringPattern.elements.push(types.identifier("".concat(dataSourceId, "_count")));
1498
- addedCountFetches.add(dataSourceId);
1499
- }
1500
- });
1501
- // Calculate and add maxPages before return
1502
- var returnStmt = tryBody.find(function (stmt) { return stmt.type === 'ReturnStatement'; });
1503
- if (returnStmt && ((_a = returnStmt.argument) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
1504
- var propsProperty = returnStmt.argument.properties.find(function (prop) {
1505
- return prop.type === 'ObjectProperty' && prop.key.name === 'props';
1506
- });
1507
- if (propsProperty && propsProperty.value.type === 'ObjectExpression') {
1508
- var propsObject_1 = propsProperty.value;
1509
- var returnIndex_1 = tryBody.indexOf(returnStmt);
1510
- paginationInfos.forEach(function (info, index) {
1511
- var paginatedVarName = "".concat(info.dataSourceIdentifier, "_pg_").concat(index);
1512
- var countVarName = "".concat(info.dataSourceIdentifier, "_count");
1513
- var maxPagesVarName = "".concat(info.dataSourceIdentifier, "_pg_").concat(index, "_maxPages");
1514
- var maxPagesCalc = types.variableDeclaration('const', [
1515
- types.variableDeclarator(types.identifier(maxPagesVarName), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
1516
- types.binaryExpression('/', types.logicalExpression('||', types.identifier(countVarName), types.numericLiteral(0)), types.numericLiteral(info.perPage)),
1104
+ // Add maxPages calculation for paginated
1105
+ if (usage.paginated) {
1106
+ var maxPagesPropName_1 = "".concat(vars.propsPrefix, "_maxPages");
1107
+ var countVarName = "".concat(usage.dataSourceIdentifier, "_count");
1108
+ // Check if maxPages calculation already exists
1109
+ var existingMaxPages = tryBlock.body.find(function (s) { var _a, _b, _c; return s.type === 'VariableDeclaration' && ((_c = (_b = (_a = s.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id) === null || _c === void 0 ? void 0 : _c.name) === maxPagesPropName_1; });
1110
+ if (!existingMaxPages) {
1111
+ // Insert maxPages calculation before return
1112
+ var returnIndex = tryBlock.body.indexOf(returnStmt);
1113
+ tryBlock.body.splice(returnIndex, 0, types.variableDeclaration('const', [
1114
+ types.variableDeclarator(types.identifier(maxPagesPropName_1), types.callExpression(types.memberExpression(types.identifier('Math'), types.identifier('ceil')), [
1115
+ types.binaryExpression('/', types.logicalExpression('||', types.identifier(countVarName), types.numericLiteral(0)), types.numericLiteral(usage.perPage)),
1517
1116
  ])),
1518
- ]);
1519
- tryBody.splice(returnIndex_1, 0, maxPagesCalc);
1520
- // Add both the paginated data and maxPages to props
1521
- propsObject_1.properties.push(types.objectProperty(types.identifier(paginatedVarName), types.identifier(paginatedVarName)));
1522
- propsObject_1.properties.push(types.objectProperty(types.identifier(maxPagesVarName), types.identifier(maxPagesVarName)));
1523
- });
1524
- }
1525
- }
1526
- }
1527
- function createAPIRoutesForPaginatedDataSources(uidlNode, dataSources, componentChunk, extractedResources, paginationInfos, isComponent) {
1528
- var paginatedDataSourceIds = new Set(paginationInfos.map(function (info) { return info.dataSourceIdentifier; }));
1529
- var searchEnabledDataSources = new Set(paginationInfos.filter(function (info) { return info.searchEnabled; }).map(function (info) { return info.dataSourceIdentifier; }));
1530
- var createdCountRoutes = new Set();
1531
- var traverseForDataSources = function (node) {
1532
- var _a;
1533
- if (!node) {
1534
- return;
1535
- }
1536
- if (node.type === 'data-source-list' || node.type === 'data-source-item') {
1537
- var renderProp = node.content.renderPropIdentifier;
1538
- if (renderProp && paginatedDataSourceIds.has(renderProp)) {
1539
- extractDataSourceIntoNextAPIFolder(node, dataSources, componentChunk, extractedResources);
1540
- var hasSearch = searchEnabledDataSources.has(renderProp);
1541
- var needsCountRoute = isComponent || hasSearch;
1542
- if (needsCountRoute) {
1543
- var resourceDef = node.content.resourceDefinition;
1544
- if (resourceDef) {
1545
- var dataSourceId = resourceDef.dataSourceId;
1546
- var tableName = resourceDef.tableName;
1547
- var dataSourceType = resourceDef.dataSourceType;
1548
- var fileName = "".concat(dataSourceType, "-").concat(tableName, "-").concat(dataSourceId.substring(0, 8));
1549
- var countFileName = "".concat(fileName, "-count");
1550
- if (!createdCountRoutes.has(countFileName)) {
1551
- extractedResources["api/".concat(countFileName)] = {
1552
- fileName: countFileName,
1553
- fileType: FileType.JS,
1554
- path: ['pages', 'api'],
1555
- content: "import dataSource from '../../utils/data-sources/".concat(fileName, "'\n\nexport default dataSource.getCount\n"),
1556
- };
1557
- createdCountRoutes.add(countFileName);
1558
- }
1559
- }
1560
- }
1117
+ ]));
1118
+ // Add maxPages to props
1119
+ propsObj.properties.push(types.objectProperty(types.identifier(maxPagesPropName_1), types.identifier(maxPagesPropName_1)));
1561
1120
  }
1562
1121
  }
1563
- if ((_a = node.content) === null || _a === void 0 ? void 0 : _a.children) {
1564
- node.content.children.forEach(function (child) { return traverseForDataSources(child); });
1565
- }
1566
- };
1567
- traverseForDataSources(uidlNode);
1568
- }
1569
- function createAPIRoutesForSearchOnlyDataSources(uidlNode, dataSources, componentChunk, extractedResources, searchOnlyDataSources) {
1570
- var searchOnlyDataSourceIds = new Set(searchOnlyDataSources.map(function (info) { return info.dataSourceIdentifier; }));
1571
- var traverseForDataSources = function (node) {
1572
- var _a;
1573
- if (!node) {
1122
+ });
1123
+ // Add count fetches for unique data sources
1124
+ dataSourcesNeedingCount.forEach(function (key) {
1125
+ var _a = key.split(':'), dataSourceType = _a[0], tableName = _a[1], dataSourceId = _a[2];
1126
+ var fileName = generateSafeFileName(dataSourceType, tableName, dataSourceId);
1127
+ // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
1128
+ var fetcherImportName = StringUtils.dashCaseToCamelCase(fileName);
1129
+ // Find usage to get dataSourceIdentifier
1130
+ var usage = registry.usages.find(function (u) {
1131
+ return u.resourceDefinition.dataSourceId === dataSourceId &&
1132
+ u.resourceDefinition.tableName === tableName;
1133
+ });
1134
+ if (!usage) {
1574
1135
  return;
1575
1136
  }
1576
- if (node.type === 'data-source-list' || node.type === 'data-source-item') {
1577
- var renderProp = node.content.renderPropIdentifier;
1578
- if (renderProp && searchOnlyDataSourceIds.has(renderProp)) {
1579
- extractDataSourceIntoNextAPIFolder(node, dataSources, componentChunk, extractedResources);
1580
- }
1581
- }
1582
- if ((_a = node.content) === null || _a === void 0 ? void 0 : _a.children) {
1583
- node.content.children.forEach(function (child) { return traverseForDataSources(child); });
1137
+ var countVarName = "".concat(usage.dataSourceIdentifier, "_count");
1138
+ // Check if count fetch already exists
1139
+ var existingCount = arrayPattern.elements.findIndex(function (el) { return (el === null || el === void 0 ? void 0 : el.type) === 'Identifier' && el.name === countVarName; });
1140
+ if (existingCount === -1) {
1141
+ arrayPattern.elements.push(types.identifier(countVarName));
1142
+ fetchesArray.elements.push(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchCount')), []));
1584
1143
  }
1585
- };
1586
- traverseForDataSources(uidlNode);
1144
+ });
1587
1145
  }
1588
- export default createNextArrayMapperPaginationPlugin();
1589
1146
  //# sourceMappingURL=pagination-plugin.js.map