@teleporthq/teleport-plugin-next-data-source 0.43.74 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/_helpers/pagination-widget-fixture.ts +95 -5
- package/__tests__/blog-adjacent-arranged.test.ts +176 -0
- package/__tests__/blog-post-contents.test.ts +212 -0
- package/__tests__/blog-post-page-enrichment.test.ts +28 -5
- package/__tests__/blog-post-picture-stand-in.test.ts +48 -0
- package/__tests__/blog-post-reading-time.test.ts +55 -0
- package/__tests__/booking-item-transform.test.ts +120 -0
- package/__tests__/browser-row-policy.test.ts +13 -3
- package/__tests__/content-preset-wiring.test.ts +108 -0
- package/__tests__/fetchers.test.ts +1 -1
- package/__tests__/fixed-list-sort.test.ts +183 -0
- package/__tests__/infinite-scroll.test.ts +154 -5
- package/__tests__/list-sort-order.test.ts +61 -0
- package/__tests__/null-filter-where.test.ts +132 -0
- package/__tests__/pagination-filter-groups.test.ts +186 -0
- package/__tests__/pg-date-parser.test.ts +73 -0
- package/__tests__/plain-list-sort.test.ts +215 -0
- package/__tests__/product-price-sort.ts +58 -25
- package/__tests__/range-control.test.ts +159 -0
- package/__tests__/rest-api-key-header.test.ts +18 -0
- package/__tests__/search-input-marker.test.ts +86 -0
- package/__tests__/search-url-sync.test.ts +61 -16
- package/__tests__/shared-resource-prefetch.test.ts +65 -0
- package/__tests__/table-read-route-protected-tables.test.ts +33 -3
- package/dist/cjs/count-effect.d.ts +7 -1
- package/dist/cjs/count-effect.d.ts.map +1 -1
- package/dist/cjs/count-effect.js +15 -5
- package/dist/cjs/count-effect.js.map +1 -1
- package/dist/cjs/fetchers/pg-client-import.d.ts +12 -0
- package/dist/cjs/fetchers/pg-client-import.d.ts.map +1 -0
- package/dist/cjs/fetchers/pg-client-import.js +15 -0
- package/dist/cjs/fetchers/pg-client-import.js.map +1 -0
- package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
- package/dist/cjs/fetchers/postgresql.js +4 -1
- package/dist/cjs/fetchers/postgresql.js.map +1 -1
- package/dist/cjs/fetchers/raw-query.d.ts.map +1 -1
- package/dist/cjs/fetchers/raw-query.js +2 -1
- package/dist/cjs/fetchers/raw-query.js.map +1 -1
- package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
- package/dist/cjs/fetchers/rest-api.js +3 -1
- package/dist/cjs/fetchers/rest-api.js.map +1 -1
- package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
- package/dist/cjs/fetchers/teleport.js +5 -2
- package/dist/cjs/fetchers/teleport.js.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts +7 -6
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.js +7 -33
- package/dist/cjs/fetchers/utils/browser-row-policy.js.map +1 -1
- package/dist/cjs/filter-utils.d.ts +19 -7
- package/dist/cjs/filter-utils.d.ts.map +1 -1
- package/dist/cjs/filter-utils.js +49 -13
- package/dist/cjs/filter-utils.js.map +1 -1
- package/dist/cjs/infinite-scroll.d.ts +25 -2
- package/dist/cjs/infinite-scroll.d.ts.map +1 -1
- package/dist/cjs/infinite-scroll.js +144 -33
- package/dist/cjs/infinite-scroll.js.map +1 -1
- package/dist/cjs/list-sort-order.d.ts +14 -0
- package/dist/cjs/list-sort-order.d.ts.map +1 -0
- package/dist/cjs/list-sort-order.js +36 -0
- package/dist/cjs/list-sort-order.js.map +1 -0
- package/dist/cjs/pagination-controls.d.ts +22 -3
- package/dist/cjs/pagination-controls.d.ts.map +1 -1
- package/dist/cjs/pagination-controls.js +29 -3
- package/dist/cjs/pagination-controls.js.map +1 -1
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +267 -212
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/product-price-sort.d.ts +0 -9
- package/dist/cjs/product-price-sort.d.ts.map +1 -1
- package/dist/cjs/product-price-sort.js +1 -13
- package/dist/cjs/product-price-sort.js.map +1 -1
- package/dist/cjs/range-control.d.ts +45 -0
- package/dist/cjs/range-control.d.ts.map +1 -0
- package/dist/cjs/range-control.js +165 -0
- package/dist/cjs/range-control.js.map +1 -0
- package/dist/cjs/row-order.d.ts +20 -0
- package/dist/cjs/row-order.d.ts.map +1 -0
- package/dist/cjs/row-order.js +46 -0
- package/dist/cjs/row-order.js.map +1 -0
- package/dist/cjs/search-input.d.ts +42 -0
- package/dist/cjs/search-input.d.ts.map +1 -0
- package/dist/cjs/search-input.js +158 -0
- package/dist/cjs/search-input.js.map +1 -0
- package/dist/cjs/sort-utils.d.ts +10 -0
- package/dist/cjs/sort-utils.d.ts.map +1 -1
- package/dist/cjs/sort-utils.js +22 -1
- package/dist/cjs/sort-utils.js.map +1 -1
- package/dist/cjs/transformations/blog-adjacent-posts.d.ts +11 -1
- package/dist/cjs/transformations/blog-adjacent-posts.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-adjacent-posts.js +14 -1
- package/dist/cjs/transformations/blog-adjacent-posts.js.map +1 -1
- package/dist/cjs/transformations/blog-comments.d.ts +1 -1
- package/dist/cjs/transformations/blog-comments.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-comments.js +1 -1
- package/dist/cjs/transformations/blog-comments.js.map +1 -1
- package/dist/cjs/transformations/blog-post.d.ts +14 -0
- package/dist/cjs/transformations/blog-post.d.ts.map +1 -1
- package/dist/cjs/transformations/blog-post.js +4 -1
- package/dist/cjs/transformations/blog-post.js.map +1 -1
- package/dist/cjs/transformations/booking-item.d.ts +24 -0
- package/dist/cjs/transformations/booking-item.d.ts.map +1 -0
- package/dist/cjs/transformations/booking-item.js +27 -0
- package/dist/cjs/transformations/booking-item.js.map +1 -0
- package/dist/cjs/transformations/heading-anchors.d.ts +32 -8
- package/dist/cjs/transformations/heading-anchors.d.ts.map +1 -1
- package/dist/cjs/transformations/heading-anchors.js +34 -10
- package/dist/cjs/transformations/heading-anchors.js.map +1 -1
- package/dist/cjs/transformations/index.d.ts +27 -13
- package/dist/cjs/transformations/index.d.ts.map +1 -1
- package/dist/cjs/transformations/index.js +73 -16
- package/dist/cjs/transformations/index.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +52 -3
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/count-effect.d.ts +7 -1
- package/dist/esm/count-effect.d.ts.map +1 -1
- package/dist/esm/count-effect.js +15 -5
- package/dist/esm/count-effect.js.map +1 -1
- package/dist/esm/fetchers/pg-client-import.d.ts +12 -0
- package/dist/esm/fetchers/pg-client-import.d.ts.map +1 -0
- package/dist/esm/fetchers/pg-client-import.js +12 -0
- package/dist/esm/fetchers/pg-client-import.js.map +1 -0
- package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
- package/dist/esm/fetchers/postgresql.js +5 -2
- package/dist/esm/fetchers/postgresql.js.map +1 -1
- package/dist/esm/fetchers/raw-query.d.ts.map +1 -1
- package/dist/esm/fetchers/raw-query.js +2 -1
- package/dist/esm/fetchers/raw-query.js.map +1 -1
- package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
- package/dist/esm/fetchers/rest-api.js +3 -1
- package/dist/esm/fetchers/rest-api.js.map +1 -1
- package/dist/esm/fetchers/teleport.d.ts.map +1 -1
- package/dist/esm/fetchers/teleport.js +6 -3
- package/dist/esm/fetchers/teleport.js.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts +7 -6
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.js +5 -31
- package/dist/esm/fetchers/utils/browser-row-policy.js.map +1 -1
- package/dist/esm/filter-utils.d.ts +19 -7
- package/dist/esm/filter-utils.d.ts.map +1 -1
- package/dist/esm/filter-utils.js +46 -12
- package/dist/esm/filter-utils.js.map +1 -1
- package/dist/esm/infinite-scroll.d.ts +25 -2
- package/dist/esm/infinite-scroll.d.ts.map +1 -1
- package/dist/esm/infinite-scroll.js +142 -32
- package/dist/esm/infinite-scroll.js.map +1 -1
- package/dist/esm/list-sort-order.d.ts +14 -0
- package/dist/esm/list-sort-order.d.ts.map +1 -0
- package/dist/esm/list-sort-order.js +32 -0
- package/dist/esm/list-sort-order.js.map +1 -0
- package/dist/esm/pagination-controls.d.ts +22 -3
- package/dist/esm/pagination-controls.d.ts.map +1 -1
- package/dist/esm/pagination-controls.js +28 -2
- package/dist/esm/pagination-controls.js.map +1 -1
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +271 -216
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/product-price-sort.d.ts +0 -9
- package/dist/esm/product-price-sort.d.ts.map +1 -1
- package/dist/esm/product-price-sort.js +0 -11
- package/dist/esm/product-price-sort.js.map +1 -1
- package/dist/esm/range-control.d.ts +45 -0
- package/dist/esm/range-control.d.ts.map +1 -0
- package/dist/esm/range-control.js +137 -0
- package/dist/esm/range-control.js.map +1 -0
- package/dist/esm/row-order.d.ts +20 -0
- package/dist/esm/row-order.d.ts.map +1 -0
- package/dist/esm/row-order.js +41 -0
- package/dist/esm/row-order.js.map +1 -0
- package/dist/esm/search-input.d.ts +42 -0
- package/dist/esm/search-input.d.ts.map +1 -0
- package/dist/esm/search-input.js +129 -0
- package/dist/esm/search-input.js.map +1 -0
- package/dist/esm/sort-utils.d.ts +10 -0
- package/dist/esm/sort-utils.d.ts.map +1 -1
- package/dist/esm/sort-utils.js +20 -0
- package/dist/esm/sort-utils.js.map +1 -1
- package/dist/esm/transformations/blog-adjacent-posts.d.ts +11 -1
- package/dist/esm/transformations/blog-adjacent-posts.d.ts.map +1 -1
- package/dist/esm/transformations/blog-adjacent-posts.js +14 -1
- package/dist/esm/transformations/blog-adjacent-posts.js.map +1 -1
- package/dist/esm/transformations/blog-comments.d.ts +1 -1
- package/dist/esm/transformations/blog-comments.d.ts.map +1 -1
- package/dist/esm/transformations/blog-comments.js +1 -1
- package/dist/esm/transformations/blog-comments.js.map +1 -1
- package/dist/esm/transformations/blog-post.d.ts +14 -0
- package/dist/esm/transformations/blog-post.d.ts.map +1 -1
- package/dist/esm/transformations/blog-post.js +4 -1
- package/dist/esm/transformations/blog-post.js.map +1 -1
- package/dist/esm/transformations/booking-item.d.ts +24 -0
- package/dist/esm/transformations/booking-item.d.ts.map +1 -0
- package/dist/esm/transformations/booking-item.js +23 -0
- package/dist/esm/transformations/booking-item.js.map +1 -0
- package/dist/esm/transformations/heading-anchors.d.ts +32 -8
- package/dist/esm/transformations/heading-anchors.d.ts.map +1 -1
- package/dist/esm/transformations/heading-anchors.js +33 -9
- package/dist/esm/transformations/heading-anchors.js.map +1 -1
- package/dist/esm/transformations/index.d.ts +27 -13
- package/dist/esm/transformations/index.d.ts.map +1 -1
- package/dist/esm/transformations/index.js +72 -16
- package/dist/esm/transformations/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +52 -3
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/count-effect.ts +31 -8
- package/src/fetchers/pg-client-import.ts +16 -0
- package/src/fetchers/postgresql.ts +25 -23
- package/src/fetchers/raw-query.ts +2 -1
- package/src/fetchers/rest-api.ts +3 -1
- package/src/fetchers/teleport.ts +22 -23
- package/src/fetchers/utils/browser-row-policy.ts +10 -20
- package/src/filter-utils.ts +102 -28
- package/src/infinite-scroll.ts +240 -79
- package/src/list-sort-order.ts +34 -0
- package/src/pagination-controls.ts +26 -3
- package/src/pagination-plugin.ts +370 -306
- package/src/product-price-sort.ts +0 -11
- package/src/range-control.ts +207 -0
- package/src/row-order.ts +55 -0
- package/src/search-input.ts +190 -0
- package/src/sort-utils.ts +25 -0
- package/src/transformations/blog-adjacent-posts.ts +89 -3
- package/src/transformations/blog-comments.ts +5 -5
- package/src/transformations/blog-post.ts +64 -13
- package/src/transformations/booking-item.ts +71 -0
- package/src/transformations/heading-anchors.ts +79 -16
- package/src/transformations/index.ts +104 -14
- package/src/utils.ts +74 -3
package/src/pagination-plugin.ts
CHANGED
|
@@ -8,11 +8,16 @@ import * as types from '@babel/types'
|
|
|
8
8
|
import { parseExpression } from '@babel/parser'
|
|
9
9
|
import { ASTStatementOrder, GenericUtils, StringUtils } from '@teleporthq/teleport-shared'
|
|
10
10
|
import { ASTUtils, URLQueryWriter, URLSearchParamSync } from '@teleporthq/teleport-plugin-common'
|
|
11
|
-
import { generateSafeFileName } from './utils'
|
|
11
|
+
import { collectFilterLeafConditions, generateSafeFileName, pruneFilterTree } from './utils'
|
|
12
12
|
import { generateDataSourceFetcherWithCore } from './data-source-fetchers'
|
|
13
13
|
import { buildProductTransformOptions, type EntityTransformOptions } from './transformations'
|
|
14
|
-
import { appendSortsParam, DynamicSortAST, extractDynamicSort } from './sort-utils'
|
|
15
|
-
import {
|
|
14
|
+
import { appendSortsParam, DynamicSortAST, extractDynamicSort, readFixedSort } from './sort-utils'
|
|
15
|
+
import {
|
|
16
|
+
appendFiltersParam,
|
|
17
|
+
buildStaticFiltersStringifyCall,
|
|
18
|
+
pushStateIdsAsDeps,
|
|
19
|
+
pushPropIdsAsDeps,
|
|
20
|
+
} from './filter-utils'
|
|
16
21
|
import { appendItemsPathParam, extractItemsPath } from './items-path'
|
|
17
22
|
import { resolveRepeaterPerPage } from './repeater-page-size'
|
|
18
23
|
import {
|
|
@@ -32,10 +37,15 @@ import {
|
|
|
32
37
|
import {
|
|
33
38
|
convertControlToButton,
|
|
34
39
|
dropInactivePaginationControls,
|
|
40
|
+
findAllPaginationControls,
|
|
35
41
|
findPaginationControl,
|
|
42
|
+
PAGINATION_FOR_ATTR,
|
|
43
|
+
readJSXAttributeString,
|
|
36
44
|
setJSXExpressionAttribute,
|
|
37
45
|
type PaginationControlKind,
|
|
38
46
|
} from './pagination-controls'
|
|
47
|
+
import { findRangeControls, wireRangeControl } from './range-control'
|
|
48
|
+
import { findAllSearchInputsInJSX, pairSearchInputs, wireSearchInput } from './search-input'
|
|
39
49
|
import { buildCountFetchEffect, buildCountSeqDeclaration } from './count-effect'
|
|
40
50
|
import {
|
|
41
51
|
findAllSearchClearButtonsInJSX,
|
|
@@ -48,6 +58,7 @@ import {
|
|
|
48
58
|
type NumberedPaginationVars,
|
|
49
59
|
} from './numbered-pagination'
|
|
50
60
|
import {
|
|
61
|
+
buildAccumulatingRequestMark,
|
|
51
62
|
buildAccumulatingResponseHandler,
|
|
52
63
|
buildInfiniteScrollDeclarations,
|
|
53
64
|
buildSentinelElement,
|
|
@@ -121,51 +132,20 @@ function searchDefaultValueInitAST(value: SearchDefaultValue | undefined): types
|
|
|
121
132
|
return types.cloneNode(value.ast, /* deep */ true) as types.Expression
|
|
122
133
|
}
|
|
123
134
|
|
|
124
|
-
// Builds the `useState(...)` initializer for the search query
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
// three products-list controls consistent.
|
|
135
|
+
// Builds the `useState(...)` initializer for the search query: the
|
|
136
|
+
// `searchDefaultValue` seed (empty string by default), never the address. A
|
|
137
|
+
// statically generated page is rendered on the server without the visitor's
|
|
138
|
+
// `?searchKeyword=`, and the browser's first render must match it — a query
|
|
139
|
+
// seeded from `window.location.search` rendered a filled input and skipped the
|
|
140
|
+
// prefetched rows there, and React warned of a hydration mismatch. A URL-bound
|
|
141
|
+
// search adopts the address after mount instead (`pushSearchUrlSyncEffects`),
|
|
142
|
+
// as the page number does (`page-url-sync.ts`).
|
|
133
143
|
//
|
|
134
144
|
// Returns a fresh AST on every call (no shared node references) so the same
|
|
135
145
|
// initializer can seed both the immediate `ds_N_searchQuery` state and the
|
|
136
146
|
// debounced `ds_N_state.debouncedQuery` value.
|
|
137
147
|
function buildSearchQueryInitAST(usage: DataSourceUsage): types.Expression {
|
|
138
|
-
|
|
139
|
-
if (!usage.searchUrlParamKey) {
|
|
140
|
-
return fallback
|
|
141
|
-
}
|
|
142
|
-
// (typeof window !== 'undefined'
|
|
143
|
-
// ? new URLSearchParams(window.location.search).get('<key>')
|
|
144
|
-
// : null) ?? <fallback>
|
|
145
|
-
return types.logicalExpression(
|
|
146
|
-
'??',
|
|
147
|
-
types.conditionalExpression(
|
|
148
|
-
types.binaryExpression(
|
|
149
|
-
'!==',
|
|
150
|
-
types.unaryExpression('typeof', types.identifier('window')),
|
|
151
|
-
types.stringLiteral('undefined')
|
|
152
|
-
),
|
|
153
|
-
types.callExpression(
|
|
154
|
-
types.memberExpression(
|
|
155
|
-
types.newExpression(types.identifier('URLSearchParams'), [
|
|
156
|
-
types.memberExpression(
|
|
157
|
-
types.memberExpression(types.identifier('window'), types.identifier('location')),
|
|
158
|
-
types.identifier('search')
|
|
159
|
-
),
|
|
160
|
-
]),
|
|
161
|
-
types.identifier('get')
|
|
162
|
-
),
|
|
163
|
-
[types.stringLiteral(usage.searchUrlParamKey)]
|
|
164
|
-
),
|
|
165
|
-
types.nullLiteral()
|
|
166
|
-
),
|
|
167
|
-
fallback
|
|
168
|
-
)
|
|
148
|
+
return searchDefaultValueInitAST(usage.searchDefaultValue)
|
|
169
149
|
}
|
|
170
150
|
|
|
171
151
|
// ==================== UIDL-FIRST STATE MANAGEMENT ====================
|
|
@@ -180,6 +160,10 @@ interface DataSourceUsage {
|
|
|
180
160
|
dataSourceIdentifier: string
|
|
181
161
|
// The cms-list-repeater renderPropIdentifier (e.g., "context_1i871")
|
|
182
162
|
arrayMapperRenderProp: string
|
|
163
|
+
// The array mapper's editor node id (`nodeId` on the cms-list-repeater), which
|
|
164
|
+
// a `range` control placed outside the pagination container names in its
|
|
165
|
+
// `data-tq-pagination-for` attribute. Absent from UIDL exported before it.
|
|
166
|
+
nodeId?: string
|
|
183
167
|
// Resource definition from UIDL
|
|
184
168
|
resourceDefinition: {
|
|
185
169
|
dataSourceId: string
|
|
@@ -213,10 +197,11 @@ interface DataSourceUsage {
|
|
|
213
197
|
// Dynamic single-column sort bound to component state (set when legacy sorts empty
|
|
214
198
|
// and cms-list-repeater declares sort/sortDirection fields)
|
|
215
199
|
dynamicSort?: DynamicSortAST
|
|
216
|
-
// Filters from resource params
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
200
|
+
// Filters from resource params, as the TREE the inspector authored: condition
|
|
201
|
+
// leaves and `{ type: 'group', operator, children }` entries (see
|
|
202
|
+
// `readFilterTree`). Anything that needs the leaves walks the tree with
|
|
203
|
+
// `collectFilterLeafConditions`; the emit sites write the tree out whole, so
|
|
204
|
+
// an `or` group reaches the data source as an `or`.
|
|
220
205
|
// tslint:disable-next-line:no-any
|
|
221
206
|
filters: any[]
|
|
222
207
|
// State IDs from dynamic filter destinations (for useMemo dependencies).
|
|
@@ -272,53 +257,26 @@ interface StateRegistry {
|
|
|
272
257
|
byArrayMapperRenderProp: Map<string, DataSourceUsage>
|
|
273
258
|
}
|
|
274
259
|
|
|
275
|
-
// The UIDL's `filters.content` array
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
//
|
|
286
|
-
// `or`-grouped conditions are flattened just like `and`-grouped ones — the
|
|
287
|
-
// downstream SQL builder always joins flat filters with `AND`, so emitting
|
|
288
|
-
// the conditions side-by-side approximates AND semantics. A future API
|
|
289
|
-
// upgrade that respects group operators would key off the original tree
|
|
290
|
-
// directly; until then, AND-flattening is the closest correct behaviour and
|
|
291
|
-
// matches what the inspector preview shows for the common single-group case
|
|
292
|
-
// the GUI emits today.
|
|
293
|
-
function flattenFilterGroups(filters: any[]): any[] {
|
|
260
|
+
// The UIDL's `filters.content` array is the tree the inspector authored:
|
|
261
|
+
// `{ type: 'group', operator: 'and' | 'or', children: [...] }` entries around
|
|
262
|
+
// `{ source, destination, operand }` conditions, nested as deep as the user
|
|
263
|
+
// grouped them. The tree is kept as it is — the generated fetchers read it with
|
|
264
|
+
// `normalizeFilterTree`, so an `or` group stays an `or`. Only junk is dropped:
|
|
265
|
+
// an entry that is neither a group nor a condition (a half-built inspector
|
|
266
|
+
// row) would otherwise reach the API as `{ source: '', destination: '' }`.
|
|
267
|
+
// Entries without an explicit `type` are the legacy flat form and are
|
|
268
|
+
// conditions.
|
|
269
|
+
function readFilterTree(filters: any[]): any[] {
|
|
294
270
|
if (!Array.isArray(filters)) {
|
|
295
271
|
return []
|
|
296
272
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
if (entry.type === 'group' && Array.isArray(entry.children)) {
|
|
303
|
-
for (const child of entry.children) {
|
|
304
|
-
walk(child)
|
|
305
|
-
}
|
|
306
|
-
return
|
|
307
|
-
}
|
|
308
|
-
// Backwards-compatible: entries without an explicit `type` (legacy flat
|
|
309
|
-
// form) and entries explicitly tagged `condition` are both treated as
|
|
310
|
-
// condition leaves.
|
|
311
|
-
if (entry.type === undefined || entry.type === 'condition') {
|
|
312
|
-
out.push(entry)
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
for (const entry of filters) {
|
|
316
|
-
walk(entry)
|
|
317
|
-
}
|
|
318
|
-
return out
|
|
273
|
+
return pruneFilterTree(
|
|
274
|
+
filters,
|
|
275
|
+
(entry: any) => entry.type === undefined || entry.type === 'condition'
|
|
276
|
+
)
|
|
319
277
|
}
|
|
320
278
|
|
|
321
|
-
// Walks
|
|
279
|
+
// Walks the filter tree to extract every `urlSearchParams` reference key
|
|
322
280
|
// (e.g. `'categoryFilter'`). Used to (a) inject `const router = useRouter()`
|
|
323
281
|
// once at the top of the component, (b) wire `router.query.<key>` into the
|
|
324
282
|
// `useMemo` dependency array so the client-side fetch reruns whenever the
|
|
@@ -327,7 +285,7 @@ function flattenFilterGroups(filters: any[]): any[] {
|
|
|
327
285
|
function collectFilterUrlSearchParamKeys(filters: any[]): string[] {
|
|
328
286
|
const seen = new Set<string>()
|
|
329
287
|
const out: string[] = []
|
|
330
|
-
for (const f of filters) {
|
|
288
|
+
for (const f of collectFilterLeafConditions(filters) as any[]) {
|
|
331
289
|
const dest = f?.destination
|
|
332
290
|
if (!ASTUtils.isUIDLDynamicReference(dest)) {
|
|
333
291
|
continue
|
|
@@ -345,6 +303,16 @@ function collectFilterUrlSearchParamKeys(filters: any[]): string[] {
|
|
|
345
303
|
return out
|
|
346
304
|
}
|
|
347
305
|
|
|
306
|
+
// The filter tree with every dynamic destination pruned — what `getStaticProps`
|
|
307
|
+
// can resolve at build time. Groups keep their operator; a group left empty by
|
|
308
|
+
// the pruning disappears with it (`pruneFilterTree`).
|
|
309
|
+
function staticFiltersOf(usage: DataSourceUsage): any[] {
|
|
310
|
+
return pruneFilterTree(
|
|
311
|
+
usage.filters || [],
|
|
312
|
+
(f: any) => !ASTUtils.isUIDLDynamicReference(f.destination)
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
|
|
348
316
|
// Returns true when any filter destination is a `urlSearchParams` dynamic
|
|
349
317
|
// reference — used by the plugin to know it needs to import `useRouter` and
|
|
350
318
|
// emit `const router = useRouter()` at the top of the component. Cheaper to
|
|
@@ -550,23 +518,28 @@ function buildStateRegistry(uidlNode: any): StateRegistry {
|
|
|
550
518
|
sorts = parentDataSource.resourceParams.sorts.content
|
|
551
519
|
}
|
|
552
520
|
|
|
553
|
-
// If legacy sorts aren't set, fall back to the
|
|
554
|
-
//
|
|
521
|
+
// If legacy sorts aren't set, fall back to the single-column sort fields
|
|
522
|
+
// on the cms-list-repeater. A FIXED one (a column chosen in the editor,
|
|
523
|
+
// e.g. a blog listing's newest first) is a static sort: read as dynamic,
|
|
524
|
+
// it made the list drop the server-side first page (`initialData` below
|
|
525
|
+
// is skipped for a dynamic sort) — the pre-rendered HTML carried no
|
|
526
|
+
// posts, and the browser fetched page 1 a second time. Only a sort
|
|
527
|
+
// bound to state (the admin panel's sortable columns) is dynamic.
|
|
555
528
|
let dynamicSort: DynamicSortAST | undefined
|
|
556
529
|
if ((!sorts || sorts.length === 0) && content.sort) {
|
|
557
|
-
|
|
530
|
+
const fixedSort = readFixedSort(content.sort, content.sortDirection)
|
|
531
|
+
if (fixedSort) {
|
|
532
|
+
sorts = [fixedSort]
|
|
533
|
+
} else {
|
|
534
|
+
dynamicSort = extractDynamicSort(content.sort, content.sortDirection)
|
|
535
|
+
}
|
|
558
536
|
}
|
|
559
537
|
|
|
560
|
-
// Extract filters from parent's resource params
|
|
561
|
-
//
|
|
562
|
-
// nested), so flatten to leaf conditions before the downstream emit
|
|
563
|
-
// sites consume `.source` / `.destination` / `.operand` directly —
|
|
564
|
-
// they expect a flat condition array. See `flattenFilterGroups`'s
|
|
565
|
-
// header comment for why AND-flattening is the correct fallback for
|
|
566
|
-
// the API endpoint's flat-condition contract.
|
|
538
|
+
// Extract filters from parent's resource params, keeping the group tree
|
|
539
|
+
// the inspector authored (see `readFilterTree`).
|
|
567
540
|
let filters: any[] = []
|
|
568
541
|
if (parentDataSource.resourceParams?.filters?.content) {
|
|
569
|
-
filters =
|
|
542
|
+
filters = readFilterTree(parentDataSource.resourceParams.filters.content)
|
|
570
543
|
}
|
|
571
544
|
|
|
572
545
|
// Split dynamic destination keys by reference type. `state`/`prop`
|
|
@@ -575,7 +548,7 @@ function buildStateRegistry(uidlNode: any): StateRegistry {
|
|
|
575
548
|
// `useRouter()` declaration injected separately.
|
|
576
549
|
const filterStateIds: string[] = []
|
|
577
550
|
const filterPropIds: string[] = []
|
|
578
|
-
for (const f of filters) {
|
|
551
|
+
for (const f of collectFilterLeafConditions(filters) as any[]) {
|
|
579
552
|
if (!ASTUtils.isUIDLDynamicReference(f.destination)) {
|
|
580
553
|
continue
|
|
581
554
|
}
|
|
@@ -640,6 +613,7 @@ function buildStateRegistry(uidlNode: any): StateRegistry {
|
|
|
640
613
|
index: index++,
|
|
641
614
|
dataSourceIdentifier: parentDataSource.identifier,
|
|
642
615
|
arrayMapperRenderProp,
|
|
616
|
+
nodeId: typeof content.nodeId === 'string' ? content.nodeId : undefined,
|
|
643
617
|
resourceDefinition: {
|
|
644
618
|
dataSourceId: parentDataSource.resourceDef.dataSourceId || '',
|
|
645
619
|
tableName: parentDataSource.resourceDef.tableName || '',
|
|
@@ -741,6 +715,9 @@ function getStateVarsForUsage(usage: DataSourceUsage): {
|
|
|
741
715
|
setPageStateVar: string
|
|
742
716
|
maxPagesStateVar: string
|
|
743
717
|
setMaxPagesStateVar: string
|
|
718
|
+
/** The counted row total behind a `range` control; `null` until counted. */
|
|
719
|
+
totalStateVar: string
|
|
720
|
+
setTotalStateVar: string
|
|
744
721
|
searchQueryVar: string
|
|
745
722
|
setSearchQueryVar: string
|
|
746
723
|
debouncedSearchQueryVar: string
|
|
@@ -759,6 +736,8 @@ function getStateVarsForUsage(usage: DataSourceUsage): {
|
|
|
759
736
|
setPageStateVar: `setDs_${idx}_page`,
|
|
760
737
|
maxPagesStateVar: `ds_${idx}_maxPages`,
|
|
761
738
|
setMaxPagesStateVar: `setDs_${idx}_maxPages`,
|
|
739
|
+
totalStateVar: `ds_${idx}_total`,
|
|
740
|
+
setTotalStateVar: `setDs_${idx}_total`,
|
|
762
741
|
searchQueryVar: `ds_${idx}_searchQuery`,
|
|
763
742
|
setSearchQueryVar: `setDs_${idx}_searchQuery`,
|
|
764
743
|
debouncedSearchQueryVar: `ds_${idx}_debouncedQuery`,
|
|
@@ -838,21 +817,127 @@ function pushSearchUrlSyncEffects(
|
|
|
838
817
|
)
|
|
839
818
|
: types.identifier(vars.debouncedSearchQueryVar)
|
|
840
819
|
|
|
820
|
+
// The query starts at its default (see `buildSearchQueryInitAST`), so the
|
|
821
|
+
// pair must agree on who goes first: the read-back adopts the address, THEN
|
|
822
|
+
// the write-back may write — before that, its first run would delete the very
|
|
823
|
+
// `?<key>=` the read-back is about to adopt.
|
|
824
|
+
const adoptedRefVar = `ds_${usage.index}_searchUrlAdopted`
|
|
825
|
+
const adopterVar = `ds_${usage.index}_adoptUrlSearch`
|
|
826
|
+
effectStatements.push(
|
|
827
|
+
types.variableDeclaration('const', [
|
|
828
|
+
types.variableDeclarator(
|
|
829
|
+
types.identifier(adoptedRefVar),
|
|
830
|
+
types.callExpression(types.identifier('useRef'), [types.booleanLiteral(false)])
|
|
831
|
+
),
|
|
832
|
+
]),
|
|
833
|
+
buildUrlSearchAdopter(adopterVar, usage, vars)
|
|
834
|
+
)
|
|
835
|
+
|
|
841
836
|
// write-back: debounced query → `?<searchUrlParamKey>=`
|
|
842
837
|
effectStatements.push(
|
|
843
838
|
URLSearchParamSync.buildUrlWriteBackEffect(
|
|
844
839
|
usage.searchUrlParamKey,
|
|
845
840
|
buildDebouncedValueExpr(),
|
|
846
|
-
buildDebouncedValueExpr()
|
|
841
|
+
buildDebouncedValueExpr(),
|
|
842
|
+
undefined,
|
|
843
|
+
adoptedRefVar
|
|
847
844
|
)
|
|
848
845
|
)
|
|
849
|
-
// read-back: `?<searchUrlParamKey>=` → input
|
|
850
|
-
//
|
|
846
|
+
// read-back: `?<searchUrlParamKey>=` → the input AND the applied query at once
|
|
847
|
+
// (`ds_N_adoptUrlSearch`), so an address is not a typed change: it skips the
|
|
848
|
+
// debounce and keeps a page the address carries — `?searchKeyword=x&page=3`
|
|
849
|
+
// lands on page 3.
|
|
851
850
|
effectStatements.push(
|
|
852
|
-
URLSearchParamSync.buildUrlReadBackEffect(
|
|
851
|
+
URLSearchParamSync.buildUrlReadBackEffect(
|
|
852
|
+
usage.searchUrlParamKey,
|
|
853
|
+
adopterVar,
|
|
854
|
+
undefined,
|
|
855
|
+
adoptedRefVar
|
|
856
|
+
)
|
|
853
857
|
)
|
|
854
858
|
}
|
|
855
859
|
|
|
860
|
+
// `const ds_N_adoptUrlSearch = (update) => { … }`: the setter the search's URL
|
|
861
|
+
// read-back calls with its `(prev) => next` updater. It moves the input and the
|
|
862
|
+
// applied (debounced) query together. A list whose page is in the address
|
|
863
|
+
// keeps its page — the page sync sets it from the same address. Any other
|
|
864
|
+
// list starts the new query on page 1, as a typed change does in the debounce
|
|
865
|
+
// effect: an appending list has usually advanced past page 1 by the time the
|
|
866
|
+
// router is ready, and the query's first answer would otherwise be its page 2
|
|
867
|
+
// — empty for a query only a few rows match.
|
|
868
|
+
function buildUrlSearchAdopter(
|
|
869
|
+
adopterVar: string,
|
|
870
|
+
usage: DataSourceUsage,
|
|
871
|
+
vars: ReturnType<typeof getStateVarsForUsage>
|
|
872
|
+
): types.VariableDeclaration {
|
|
873
|
+
const update = types.identifier('update')
|
|
874
|
+
const pageReset = usageHasPageUrlSync(usage)
|
|
875
|
+
? []
|
|
876
|
+
: [types.objectProperty(types.identifier('page'), types.numericLiteral(1))]
|
|
877
|
+
const applyToDebounced =
|
|
878
|
+
usage.category === 'paginated+search'
|
|
879
|
+
? // setDs_N_state((state) => {
|
|
880
|
+
// const next = update(state.debouncedQuery)
|
|
881
|
+
// return next === state.debouncedQuery ? state : { ...state, page: 1, debouncedQuery: next }
|
|
882
|
+
// })
|
|
883
|
+
types.callExpression(types.identifier(vars.setCombinedStateVar), [
|
|
884
|
+
types.arrowFunctionExpression(
|
|
885
|
+
[types.identifier('state')],
|
|
886
|
+
types.blockStatement([
|
|
887
|
+
types.variableDeclaration('const', [
|
|
888
|
+
types.variableDeclarator(
|
|
889
|
+
types.identifier('next'),
|
|
890
|
+
types.callExpression(types.identifier('update'), [
|
|
891
|
+
types.memberExpression(
|
|
892
|
+
types.identifier('state'),
|
|
893
|
+
types.identifier('debouncedQuery')
|
|
894
|
+
),
|
|
895
|
+
])
|
|
896
|
+
),
|
|
897
|
+
]),
|
|
898
|
+
types.returnStatement(
|
|
899
|
+
types.conditionalExpression(
|
|
900
|
+
types.binaryExpression(
|
|
901
|
+
'===',
|
|
902
|
+
types.identifier('next'),
|
|
903
|
+
types.memberExpression(
|
|
904
|
+
types.identifier('state'),
|
|
905
|
+
types.identifier('debouncedQuery')
|
|
906
|
+
)
|
|
907
|
+
),
|
|
908
|
+
types.identifier('state'),
|
|
909
|
+
types.objectExpression([
|
|
910
|
+
types.spreadElement(types.identifier('state')),
|
|
911
|
+
...pageReset,
|
|
912
|
+
types.objectProperty(
|
|
913
|
+
types.identifier('debouncedQuery'),
|
|
914
|
+
types.identifier('next')
|
|
915
|
+
),
|
|
916
|
+
])
|
|
917
|
+
)
|
|
918
|
+
),
|
|
919
|
+
])
|
|
920
|
+
),
|
|
921
|
+
])
|
|
922
|
+
: types.callExpression(types.identifier(vars.setDebouncedSearchQueryVar), [update])
|
|
923
|
+
return types.variableDeclaration('const', [
|
|
924
|
+
types.variableDeclarator(
|
|
925
|
+
types.identifier(adopterVar),
|
|
926
|
+
types.arrowFunctionExpression(
|
|
927
|
+
[types.identifier('update')],
|
|
928
|
+
types.blockStatement([
|
|
929
|
+
types.expressionStatement(
|
|
930
|
+
types.callExpression(types.identifier(vars.setSearchQueryVar), [
|
|
931
|
+
types.identifier('update'),
|
|
932
|
+
])
|
|
933
|
+
),
|
|
934
|
+
types.expressionStatement(applyToDebounced),
|
|
935
|
+
])
|
|
936
|
+
)
|
|
937
|
+
),
|
|
938
|
+
])
|
|
939
|
+
}
|
|
940
|
+
|
|
856
941
|
// How one usage reads and writes its current page.
|
|
857
942
|
//
|
|
858
943
|
// A paginated+search list keeps the page inside a combined
|
|
@@ -1126,6 +1211,14 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1126
1211
|
}
|
|
1127
1212
|
const blockStatement = arrowFunction.body as types.BlockStatement
|
|
1128
1213
|
|
|
1214
|
+
// The "Showing 1–8 of 12" texts. Known up front because a component that
|
|
1215
|
+
// draws one needs the counted TOTAL in state — `ds_N_maxPages` alone cannot
|
|
1216
|
+
// say how many rows there are — and that state, with the live count that
|
|
1217
|
+
// fills it, is declared per usage below. A component without one emits
|
|
1218
|
+
// exactly what it always did.
|
|
1219
|
+
const rangeControls = findRangeControls(blockStatement)
|
|
1220
|
+
const hasRangeControl = rangeControls.length > 0
|
|
1221
|
+
|
|
1129
1222
|
// STEP 1: Build state registry from UIDL
|
|
1130
1223
|
const registry = buildStateRegistry(uidl.node)
|
|
1131
1224
|
|
|
@@ -1258,13 +1351,12 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1258
1351
|
])
|
|
1259
1352
|
)
|
|
1260
1353
|
|
|
1261
|
-
// Immediate search query state — seeded with `searchDefaultValue
|
|
1262
|
-
// the
|
|
1263
|
-
//
|
|
1264
|
-
//
|
|
1265
|
-
//
|
|
1266
|
-
//
|
|
1267
|
-
// DataProvider to fetch instead of reusing the unfiltered SSG prefetch.
|
|
1354
|
+
// Immediate search query state — seeded with `searchDefaultValue`, like
|
|
1355
|
+
// the debounced value above. A deep-linked `?searchKeyword=` is adopted
|
|
1356
|
+
// after mount by the URL read-back, which sets both at once; the
|
|
1357
|
+
// paginated+search `initialData` is gated on `!ds_N_state.debouncedQuery`,
|
|
1358
|
+
// so the adopted query makes the DataProvider fetch filtered rows
|
|
1359
|
+
// instead of reusing the unfiltered SSG prefetch the first render shows.
|
|
1268
1360
|
stateDeclarations.push(
|
|
1269
1361
|
types.variableDeclaration('const', [
|
|
1270
1362
|
types.variableDeclarator(
|
|
@@ -1441,12 +1533,16 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1441
1533
|
pushPropIdsAsDeps(countEffectDeps, countEffectSeen, usage.filterPropIds)
|
|
1442
1534
|
// Same goes for URL-driven filters (already documented above).
|
|
1443
1535
|
pushUrlSearchParamMemoDeps(countEffectDeps, usage)
|
|
1536
|
+
if (hasRangeControl) {
|
|
1537
|
+
stateDeclarations.push(buildTotalDeclaration(vars))
|
|
1538
|
+
}
|
|
1444
1539
|
stateDeclarations.push(buildCountSeqDeclaration(vars.countSeqRefVar))
|
|
1445
1540
|
effectStatements.push(
|
|
1446
1541
|
buildCountFetchEffect({
|
|
1447
1542
|
fileName,
|
|
1448
1543
|
perPage: usage.perPage,
|
|
1449
1544
|
setMaxPagesVar: vars.setMaxPagesStateVar,
|
|
1545
|
+
setTotalVar: hasRangeControl ? vars.setTotalStateVar : undefined,
|
|
1450
1546
|
urlParams,
|
|
1451
1547
|
deps: countEffectDeps,
|
|
1452
1548
|
countSeqRefVar: vars.countSeqRefVar,
|
|
@@ -1513,8 +1609,10 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1513
1609
|
// "Next" button, but not to label a numbered strip or to know when an
|
|
1514
1610
|
// infinite list has reached its end, so those two modes fetch a live
|
|
1515
1611
|
// count as well.
|
|
1612
|
+
// A range text needs the live count too: the build-time count only
|
|
1613
|
+
// ever became a page count, never the total it shows.
|
|
1516
1614
|
const needsLiveCount =
|
|
1517
|
-
!isPage || usage.paginationMode === 'numbered' || usage.infiniteScroll
|
|
1615
|
+
!isPage || usage.paginationMode === 'numbered' || usage.infiniteScroll || hasRangeControl
|
|
1518
1616
|
if (needsLiveCount) {
|
|
1519
1617
|
const fileName = generateSafeFileName(
|
|
1520
1618
|
usage.resourceDefinition.dataSourceType,
|
|
@@ -1551,12 +1649,16 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1551
1649
|
pushPropIdsAsDeps(countDeps, countDepsSeen, usage.filterPropIds)
|
|
1552
1650
|
pushUrlSearchParamMemoDeps(countDeps, usage)
|
|
1553
1651
|
|
|
1652
|
+
if (hasRangeControl) {
|
|
1653
|
+
stateDeclarations.push(buildTotalDeclaration(vars))
|
|
1654
|
+
}
|
|
1554
1655
|
stateDeclarations.push(buildCountSeqDeclaration(vars.countSeqRefVar))
|
|
1555
1656
|
effectStatements.push(
|
|
1556
1657
|
buildCountFetchEffect({
|
|
1557
1658
|
fileName,
|
|
1558
1659
|
perPage: usage.perPage,
|
|
1559
1660
|
setMaxPagesVar: vars.setMaxPagesStateVar,
|
|
1661
|
+
setTotalVar: hasRangeControl ? vars.setTotalStateVar : undefined,
|
|
1560
1662
|
urlParams: countUrlParams,
|
|
1561
1663
|
deps: countDeps,
|
|
1562
1664
|
countSeqRefVar: vars.countSeqRefVar,
|
|
@@ -1809,10 +1911,8 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1809
1911
|
// An auto-loading list needs something at the end of the rows for its
|
|
1810
1912
|
// IntersectionObserver to watch.
|
|
1811
1913
|
if (usage.infiniteScroll && usage.paginated && !usage.infiniteScrollLoadMore) {
|
|
1812
|
-
insertSentinelAfterProvider(
|
|
1813
|
-
|
|
1814
|
-
dp,
|
|
1815
|
-
buildSentinelElement(getInfiniteScrollVars(usage.index))
|
|
1914
|
+
insertSentinelAfterProvider(blockStatement, dp, (parentTag) =>
|
|
1915
|
+
buildSentinelElement(getInfiniteScrollVars(usage.index), parentTag)
|
|
1816
1916
|
)
|
|
1817
1917
|
}
|
|
1818
1918
|
|
|
@@ -1881,25 +1981,17 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1881
1981
|
stabilizeDataProviderWithoutRepeater(dp)
|
|
1882
1982
|
})
|
|
1883
1983
|
|
|
1884
|
-
// STEP 4: Wire search inputs
|
|
1885
|
-
//
|
|
1984
|
+
// STEP 4: Wire search inputs — a platform input by its place among the
|
|
1985
|
+
// search-enabled mappers, a page's own marked input by the mapper it names
|
|
1986
|
+
// (`search-input.ts`).
|
|
1886
1987
|
const searchInputs = findAllSearchInputsInJSX(blockStatement)
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
const usageBySearchInput = new Map<any, DataSourceUsage>()
|
|
1893
|
-
searchInputs.forEach((input, idx) => {
|
|
1894
|
-
if (idx >= searchEnabledUsages.length) {
|
|
1895
|
-
return
|
|
1988
|
+
const usageBySearchInput = pairSearchInputs(searchInputs, registry.usages)
|
|
1989
|
+
for (const input of searchInputs) {
|
|
1990
|
+
const usage = usageBySearchInput.get(input.node)
|
|
1991
|
+
if (usage) {
|
|
1992
|
+
wireSearchInput(input, getStateVarsForUsage(usage))
|
|
1896
1993
|
}
|
|
1897
|
-
|
|
1898
|
-
const usage = searchEnabledUsages[idx]
|
|
1899
|
-
const vars = getStateVarsForUsage(usage)
|
|
1900
|
-
wireSearchInput(input.node, vars)
|
|
1901
|
-
usageBySearchInput.set(input.node, usage)
|
|
1902
|
-
})
|
|
1994
|
+
}
|
|
1903
1995
|
|
|
1904
1996
|
// STEP 4.5: Wire the clear buttons, each to the input it shares a parent with.
|
|
1905
1997
|
findAllSearchClearButtonsInJSX(blockStatement).forEach((button) => {
|
|
@@ -1938,6 +2030,25 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1938
2030
|
}
|
|
1939
2031
|
)
|
|
1940
2032
|
|
|
2033
|
+
// STEP 5b: Wire the range texts that name their mapper.
|
|
2034
|
+
//
|
|
2035
|
+
// A `range` control carrying `data-tq-pagination-for` belongs to the mapper
|
|
2036
|
+
// whose editor node id it names, wherever it sits — a template's footer or
|
|
2037
|
+
// toolbar is laid out by the author, not inside a pagination container, so
|
|
2038
|
+
// the container-ownership rule above cannot reach it. One without the
|
|
2039
|
+
// attribute was wired by its container in STEP 5; one naming a mapper this
|
|
2040
|
+
// component does not render stays as drawn.
|
|
2041
|
+
rangeControls.forEach((control) => {
|
|
2042
|
+
const ownerNodeId = readJSXAttributeString(control, PAGINATION_FOR_ATTR)
|
|
2043
|
+
if (!ownerNodeId) {
|
|
2044
|
+
return
|
|
2045
|
+
}
|
|
2046
|
+
const owner = registry.usages.find((usage) => usage.nodeId === ownerNodeId)
|
|
2047
|
+
if (owner) {
|
|
2048
|
+
wireRangeControlFor(control, owner, getStateVarsForUsage(owner))
|
|
2049
|
+
}
|
|
2050
|
+
})
|
|
2051
|
+
|
|
1941
2052
|
// STEP 6: Update getStaticProps if this is a page
|
|
1942
2053
|
if (isPage) {
|
|
1943
2054
|
updateGetStaticProps(
|
|
@@ -1964,6 +2075,8 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1964
2075
|
* It has to be a sibling: the provider's own child is a render-prop function,
|
|
1965
2076
|
* and anything placed inside it would be re-created on every fetch — the
|
|
1966
2077
|
* observer would then be watching an element that is no longer in the document.
|
|
2078
|
+
* The sentinel is built for the element it lands in (`buildSentinelElement`):
|
|
2079
|
+
* a fragment is transparent, a component's children may go anywhere.
|
|
1967
2080
|
*
|
|
1968
2081
|
* Returns false when the provider has no element parent to splice into (a
|
|
1969
2082
|
* provider returned directly from the component), leaving the list on its
|
|
@@ -1972,35 +2085,53 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
|
|
|
1972
2085
|
function insertSentinelAfterProvider(
|
|
1973
2086
|
blockStatement: types.BlockStatement,
|
|
1974
2087
|
provider: any,
|
|
1975
|
-
|
|
2088
|
+
buildSentinel: (parentTag: string | null) => types.JSXElement
|
|
1976
2089
|
): boolean {
|
|
1977
2090
|
let inserted = false
|
|
1978
2091
|
|
|
1979
|
-
const
|
|
2092
|
+
const elementTagOf = (node: any, enclosing: string | null): string | null => {
|
|
2093
|
+
if (node?.type === 'JSXFragment') {
|
|
2094
|
+
return enclosing
|
|
2095
|
+
}
|
|
2096
|
+
if (node?.type !== 'JSXElement') {
|
|
2097
|
+
return enclosing
|
|
2098
|
+
}
|
|
2099
|
+
const name = node.openingElement?.name
|
|
2100
|
+
if (name?.type !== 'JSXIdentifier') {
|
|
2101
|
+
return null
|
|
2102
|
+
}
|
|
2103
|
+
if (name.name === 'Fragment') {
|
|
2104
|
+
return enclosing
|
|
2105
|
+
}
|
|
2106
|
+
return /^[a-z]/.test(name.name) ? name.name : null
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
const traverse = (node: any, enclosing: string | null): void => {
|
|
1980
2110
|
if (!node || inserted) {
|
|
1981
2111
|
return
|
|
1982
2112
|
}
|
|
2113
|
+
const tag = elementTagOf(node, enclosing)
|
|
1983
2114
|
if (Array.isArray(node.children)) {
|
|
1984
2115
|
const at = node.children.indexOf(provider)
|
|
1985
2116
|
if (at !== -1) {
|
|
1986
|
-
node.children.splice(at + 1, 0,
|
|
2117
|
+
node.children.splice(at + 1, 0, buildSentinel(tag))
|
|
1987
2118
|
inserted = true
|
|
1988
2119
|
return
|
|
1989
2120
|
}
|
|
1990
|
-
node.children.forEach(traverse)
|
|
2121
|
+
node.children.forEach((child: any) => traverse(child, tag))
|
|
1991
2122
|
}
|
|
1992
2123
|
if (node.body) {
|
|
1993
2124
|
if (Array.isArray(node.body)) {
|
|
1994
|
-
node.body.forEach(traverse)
|
|
2125
|
+
node.body.forEach((child: any) => traverse(child, tag))
|
|
1995
2126
|
} else {
|
|
1996
|
-
traverse(node.body)
|
|
2127
|
+
traverse(node.body, tag)
|
|
1997
2128
|
}
|
|
1998
2129
|
}
|
|
1999
2130
|
if (node.consequent) {
|
|
2000
|
-
traverse(node.consequent)
|
|
2131
|
+
traverse(node.consequent, tag)
|
|
2001
2132
|
}
|
|
2002
2133
|
if (node.alternate) {
|
|
2003
|
-
traverse(node.alternate)
|
|
2134
|
+
traverse(node.alternate, tag)
|
|
2004
2135
|
}
|
|
2005
2136
|
// `{activeTabIndex === 0 && (<div>…<DataProvider/>…</div>)}` — a tab
|
|
2006
2137
|
// panel, a gated section: the provider sits on the RIGHT of a logical
|
|
@@ -2008,23 +2139,23 @@ function insertSentinelAfterProvider(
|
|
|
2008
2139
|
// an argument. Left unvisited, the products list under the first tab of
|
|
2009
2140
|
// a shop was never paginated or seeded, and rendered nothing.
|
|
2010
2141
|
if (node.left) {
|
|
2011
|
-
traverse(node.left)
|
|
2142
|
+
traverse(node.left, tag)
|
|
2012
2143
|
}
|
|
2013
2144
|
if (node.right) {
|
|
2014
|
-
traverse(node.right)
|
|
2145
|
+
traverse(node.right, tag)
|
|
2015
2146
|
}
|
|
2016
2147
|
if (node.test) {
|
|
2017
|
-
traverse(node.test)
|
|
2148
|
+
traverse(node.test, tag)
|
|
2018
2149
|
}
|
|
2019
2150
|
if (node.expression) {
|
|
2020
|
-
traverse(node.expression)
|
|
2151
|
+
traverse(node.expression, tag)
|
|
2021
2152
|
}
|
|
2022
2153
|
if (node.argument) {
|
|
2023
|
-
traverse(node.argument)
|
|
2154
|
+
traverse(node.argument, tag)
|
|
2024
2155
|
}
|
|
2025
2156
|
}
|
|
2026
2157
|
|
|
2027
|
-
traverse(blockStatement)
|
|
2158
|
+
traverse(blockStatement, null)
|
|
2028
2159
|
return inserted
|
|
2029
2160
|
}
|
|
2030
2161
|
|
|
@@ -2140,68 +2271,6 @@ function findArrayMapperRenderPropInDataProvider(dataProvider: any): string | un
|
|
|
2140
2271
|
return renderItemAttr.value.expression.params[0].name
|
|
2141
2272
|
}
|
|
2142
2273
|
|
|
2143
|
-
function findAllSearchInputsInJSX(
|
|
2144
|
-
blockStatement: types.BlockStatement
|
|
2145
|
-
): Array<{ node: any; className: string }> {
|
|
2146
|
-
const results: Array<{ node: any; className: string }> = []
|
|
2147
|
-
|
|
2148
|
-
const traverse = (node: any): void => {
|
|
2149
|
-
if (!node) {
|
|
2150
|
-
return
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
if (node.type === 'JSXElement' && node.openingElement?.name?.name === 'input') {
|
|
2154
|
-
const classAttr = node.openingElement.attributes?.find(
|
|
2155
|
-
(attr: any) => attr.type === 'JSXAttribute' && attr.name.name === 'className'
|
|
2156
|
-
)
|
|
2157
|
-
const className = classAttr?.value?.value || classAttr?.value?.expression?.value || ''
|
|
2158
|
-
if (className.includes('search-input')) {
|
|
2159
|
-
results.push({ node, className })
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
|
-
if (node.children && Array.isArray(node.children)) {
|
|
2164
|
-
node.children.forEach((c: any) => traverse(c))
|
|
2165
|
-
}
|
|
2166
|
-
if (node.body) {
|
|
2167
|
-
if (Array.isArray(node.body)) {
|
|
2168
|
-
node.body.forEach((s: any) => traverse(s))
|
|
2169
|
-
} else {
|
|
2170
|
-
traverse(node.body)
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
if (node.consequent) {
|
|
2174
|
-
traverse(node.consequent)
|
|
2175
|
-
}
|
|
2176
|
-
if (node.alternate) {
|
|
2177
|
-
traverse(node.alternate)
|
|
2178
|
-
}
|
|
2179
|
-
// `{activeTabIndex === 0 && (<div>…<DataProvider/>…</div>)}` — a tab
|
|
2180
|
-
// panel, a gated section: the provider sits on the RIGHT of a logical
|
|
2181
|
-
// expression (or in a ternary's `test`), which is not a child, a body or
|
|
2182
|
-
// an argument. Left unvisited, the products list under the first tab of
|
|
2183
|
-
// a shop was never paginated or seeded, and rendered nothing.
|
|
2184
|
-
if (node.left) {
|
|
2185
|
-
traverse(node.left)
|
|
2186
|
-
}
|
|
2187
|
-
if (node.right) {
|
|
2188
|
-
traverse(node.right)
|
|
2189
|
-
}
|
|
2190
|
-
if (node.test) {
|
|
2191
|
-
traverse(node.test)
|
|
2192
|
-
}
|
|
2193
|
-
if (node.expression) {
|
|
2194
|
-
traverse(node.expression)
|
|
2195
|
-
}
|
|
2196
|
-
if (node.argument) {
|
|
2197
|
-
traverse(node.argument)
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
traverse(blockStatement)
|
|
2202
|
-
return results
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
2274
|
/**
|
|
2206
2275
|
* Every pagination widget in the JSX, paired with the mapper it belongs to.
|
|
2207
2276
|
*
|
|
@@ -2736,6 +2805,15 @@ function updateDataProviderForPlain(
|
|
|
2736
2805
|
usage: DataSourceUsage,
|
|
2737
2806
|
localized: boolean
|
|
2738
2807
|
): void {
|
|
2808
|
+
// A sort bound to state is the visitor's, which the server cannot know: rows
|
|
2809
|
+
// pre-rendered in the table's order would stand in for it, since a seeded
|
|
2810
|
+
// provider skips its first fetch — the paginated lists drop them the same way.
|
|
2811
|
+
if (usage.dynamicSort) {
|
|
2812
|
+
dp.openingElement.attributes = dp.openingElement.attributes.filter(
|
|
2813
|
+
(attr: any) => !(attr.type === 'JSXAttribute' && attr.name?.name === 'initialData')
|
|
2814
|
+
)
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2739
2817
|
const attrs = dp.openingElement.attributes
|
|
2740
2818
|
|
|
2741
2819
|
const clientCache = usage.cache?.client ? usage.cache : undefined
|
|
@@ -2774,13 +2852,15 @@ function updateDataProviderForPlain(
|
|
|
2774
2852
|
|
|
2775
2853
|
// Find the params attribute. A plain list may have none at all — but the
|
|
2776
2854
|
// fetch it was just given sends `params` regardless, and in a localized
|
|
2777
|
-
// project those have to carry the locale,
|
|
2855
|
+
// project those have to carry the locale, and a sorted list its sort, so the
|
|
2856
|
+
// attribute is created.
|
|
2778
2857
|
let paramsAttrIndex = attrs.findIndex(
|
|
2779
2858
|
(attr: any) => attr.type === 'JSXAttribute' && attr.name.name === 'params'
|
|
2780
2859
|
)
|
|
2860
|
+
const isSorted = usage.sorts.length > 0 || !!usage.dynamicSort
|
|
2781
2861
|
|
|
2782
2862
|
if (paramsAttrIndex === -1) {
|
|
2783
|
-
if (!localized) {
|
|
2863
|
+
if (!localized && !isSorted) {
|
|
2784
2864
|
return
|
|
2785
2865
|
}
|
|
2786
2866
|
attrs.push(
|
|
@@ -2814,10 +2894,22 @@ function updateDataProviderForPlain(
|
|
|
2814
2894
|
return
|
|
2815
2895
|
}
|
|
2816
2896
|
|
|
2817
|
-
//
|
|
2897
|
+
// The repeater's sort, which the paginated and searchable lists add to the
|
|
2898
|
+
// params they rebuild: kept as they come, a plain list's params never
|
|
2899
|
+
// carried it, and the rows arrived in the table's own order.
|
|
2900
|
+
if (paramsExpression.type === 'ObjectExpression' && !hasObjectKey(paramsExpression, 'sorts')) {
|
|
2901
|
+
appendSortsParam(
|
|
2902
|
+
paramsExpression.properties as types.ObjectProperty[],
|
|
2903
|
+
usage.sorts,
|
|
2904
|
+
usage.dynamicSort
|
|
2905
|
+
)
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
// Build useMemo dependencies including filter state IDs and a dynamic sort's state
|
|
2818
2909
|
const memoDeps: types.Expression[] = []
|
|
2819
2910
|
const memoSeen = new Set<string>()
|
|
2820
2911
|
pushStateIdsAsDeps(memoDeps, memoSeen, usage.filterStateIds)
|
|
2912
|
+
pushStateIdsAsDeps(memoDeps, memoSeen, usage.dynamicSort?.depStateIds ?? [])
|
|
2821
2913
|
pushPropIdsAsDeps(memoDeps, memoSeen, usage.filterPropIds)
|
|
2822
2914
|
pushUrlSearchParamMemoDeps(memoDeps, usage)
|
|
2823
2915
|
if (localized && paramsExpression.type === 'ObjectExpression') {
|
|
@@ -2837,6 +2929,14 @@ function updateDataProviderForPlain(
|
|
|
2837
2929
|
)
|
|
2838
2930
|
}
|
|
2839
2931
|
|
|
2932
|
+
const hasObjectKey = (object: types.ObjectExpression, key: string): boolean =>
|
|
2933
|
+
object.properties.some(
|
|
2934
|
+
(property) =>
|
|
2935
|
+
property.type === 'ObjectProperty' &&
|
|
2936
|
+
((property.key.type === 'Identifier' && property.key.name === key) ||
|
|
2937
|
+
(property.key.type === 'StringLiteral' && property.key.value === key))
|
|
2938
|
+
)
|
|
2939
|
+
|
|
2840
2940
|
function stabilizeDataProviderWithoutRepeater(dp: any): void {
|
|
2841
2941
|
const attrs = dp.openingElement.attributes
|
|
2842
2942
|
|
|
@@ -2967,11 +3067,21 @@ function createFetchDataAttribute(
|
|
|
2967
3067
|
[responseTail]
|
|
2968
3068
|
)
|
|
2969
3069
|
|
|
3070
|
+
// An appending list records the request it now stands on before making it
|
|
3071
|
+
// (see `buildAccumulatingRequestMark`).
|
|
2970
3072
|
const arrow = cache
|
|
2971
3073
|
? types.arrowFunctionExpression(
|
|
2972
3074
|
[types.identifier('params')],
|
|
2973
3075
|
buildCachedFetchBody(networkChain, cache)
|
|
2974
3076
|
)
|
|
3077
|
+
: accumulate
|
|
3078
|
+
? types.arrowFunctionExpression(
|
|
3079
|
+
[types.identifier('params')],
|
|
3080
|
+
types.blockStatement([
|
|
3081
|
+
buildAccumulatingRequestMark(getInfiniteScrollVars(accumulate.usage.index)),
|
|
3082
|
+
types.returnStatement(networkChain),
|
|
3083
|
+
])
|
|
3084
|
+
)
|
|
2975
3085
|
: types.arrowFunctionExpression([types.identifier('params')], networkChain)
|
|
2976
3086
|
|
|
2977
3087
|
return types.jsxAttribute(
|
|
@@ -2982,39 +3092,6 @@ function createFetchDataAttribute(
|
|
|
2982
3092
|
)
|
|
2983
3093
|
}
|
|
2984
3094
|
|
|
2985
|
-
function wireSearchInput(inputNode: any, vars: ReturnType<typeof getStateVarsForUsage>): void {
|
|
2986
|
-
// Remove existing onChange and value
|
|
2987
|
-
inputNode.openingElement.attributes = inputNode.openingElement.attributes.filter(
|
|
2988
|
-
(attr: any) => !['onChange', 'value'].includes(attr.name?.name)
|
|
2989
|
-
)
|
|
2990
|
-
|
|
2991
|
-
// Add onChange
|
|
2992
|
-
inputNode.openingElement.attributes.push(
|
|
2993
|
-
types.jsxAttribute(
|
|
2994
|
-
types.jsxIdentifier('onChange'),
|
|
2995
|
-
types.jsxExpressionContainer(
|
|
2996
|
-
types.arrowFunctionExpression(
|
|
2997
|
-
[types.identifier('e')],
|
|
2998
|
-
types.callExpression(types.identifier(vars.setSearchQueryVar), [
|
|
2999
|
-
types.memberExpression(
|
|
3000
|
-
types.memberExpression(types.identifier('e'), types.identifier('target')),
|
|
3001
|
-
types.identifier('value')
|
|
3002
|
-
),
|
|
3003
|
-
])
|
|
3004
|
-
)
|
|
3005
|
-
)
|
|
3006
|
-
)
|
|
3007
|
-
)
|
|
3008
|
-
|
|
3009
|
-
// Add value
|
|
3010
|
-
inputNode.openingElement.attributes.push(
|
|
3011
|
-
types.jsxAttribute(
|
|
3012
|
-
types.jsxIdentifier('value'),
|
|
3013
|
-
types.jsxExpressionContainer(types.identifier(vars.searchQueryVar))
|
|
3014
|
-
)
|
|
3015
|
-
)
|
|
3016
|
-
}
|
|
3017
|
-
|
|
3018
3095
|
/**
|
|
3019
3096
|
* The `fetchData` attribute for one paginated usage.
|
|
3020
3097
|
*
|
|
@@ -3030,6 +3107,41 @@ function buildFetchDataForUsage(fileName: string, usage: DataSourceUsage): types
|
|
|
3030
3107
|
return createFetchDataAttribute(fileName, usage.cache?.client ? usage.cache : undefined)
|
|
3031
3108
|
}
|
|
3032
3109
|
|
|
3110
|
+
/** `const [ds_N_total, setDs_N_total] = useState(null)` — declared only beside a range control. */
|
|
3111
|
+
function buildTotalDeclaration(vars: ReturnType<typeof getStateVarsForUsage>): types.Statement {
|
|
3112
|
+
return types.variableDeclaration('const', [
|
|
3113
|
+
types.variableDeclarator(
|
|
3114
|
+
types.arrayPattern([
|
|
3115
|
+
types.identifier(vars.totalStateVar),
|
|
3116
|
+
types.identifier(vars.setTotalStateVar),
|
|
3117
|
+
]),
|
|
3118
|
+
types.callExpression(types.identifier('useState'), [types.nullLiteral()])
|
|
3119
|
+
),
|
|
3120
|
+
])
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
/**
|
|
3124
|
+
* Fills one `range` text with the live row range of `usage` (see
|
|
3125
|
+
* `range-control.ts`). A mapper that does not page has no count to show, so
|
|
3126
|
+
* its range text is left as drawn.
|
|
3127
|
+
*/
|
|
3128
|
+
function wireRangeControlFor(
|
|
3129
|
+
control: any,
|
|
3130
|
+
usage: DataSourceUsage,
|
|
3131
|
+
vars: ReturnType<typeof getStateVarsForUsage>
|
|
3132
|
+
): void {
|
|
3133
|
+
if (!usage.paginated) {
|
|
3134
|
+
return
|
|
3135
|
+
}
|
|
3136
|
+
const { currentPageExpr } = getPageAccessors(usage, vars)
|
|
3137
|
+
wireRangeControl(control, {
|
|
3138
|
+
totalVar: vars.totalStateVar,
|
|
3139
|
+
currentPageExpr: currentPageExpr(),
|
|
3140
|
+
perPage: usage.perPage,
|
|
3141
|
+
infiniteScroll: usage.infiniteScroll,
|
|
3142
|
+
})
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3033
3145
|
/**
|
|
3034
3146
|
* Wires the authored Load More button of an appending list.
|
|
3035
3147
|
*
|
|
@@ -3095,6 +3207,12 @@ function wirePaginationWidget(
|
|
|
3095
3207
|
vars: ReturnType<typeof getStateVarsForUsage>,
|
|
3096
3208
|
hasLoadingState: boolean
|
|
3097
3209
|
): void {
|
|
3210
|
+
// A range text inside the container takes the container's owner, like the
|
|
3211
|
+
// buttons beside it; one naming its own mapper is wired in STEP 5b instead.
|
|
3212
|
+
findAllPaginationControls(paginationNode, 'range')
|
|
3213
|
+
.filter((control) => !readJSXAttributeString(control, PAGINATION_FOR_ATTR))
|
|
3214
|
+
.forEach((control) => wireRangeControlFor(control, usage, vars))
|
|
3215
|
+
|
|
3098
3216
|
if (usage.infiniteScroll) {
|
|
3099
3217
|
// Only the Load More button survives; page controls make no sense for a
|
|
3100
3218
|
// list the visitor never leaves.
|
|
@@ -3650,38 +3768,12 @@ function updateGetStaticProps(
|
|
|
3650
3768
|
|
|
3651
3769
|
// Add filters if present
|
|
3652
3770
|
// Filter out dynamic destinations for getStaticProps (they can't be resolved at build time)
|
|
3653
|
-
const staticFilters = (usage
|
|
3654
|
-
(f: any) => !ASTUtils.isUIDLDynamicReference(f.destination)
|
|
3655
|
-
)
|
|
3771
|
+
const staticFilters = staticFiltersOf(usage)
|
|
3656
3772
|
if (staticFilters.length > 0) {
|
|
3657
3773
|
fetchParams.push(
|
|
3658
3774
|
types.objectProperty(
|
|
3659
3775
|
types.identifier('filters'),
|
|
3660
|
-
|
|
3661
|
-
types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
|
|
3662
|
-
[
|
|
3663
|
-
types.arrayExpression(
|
|
3664
|
-
staticFilters.map((filter: any) =>
|
|
3665
|
-
types.objectExpression([
|
|
3666
|
-
types.objectProperty(
|
|
3667
|
-
types.identifier('source'),
|
|
3668
|
-
types.stringLiteral(filter.source || '')
|
|
3669
|
-
),
|
|
3670
|
-
types.objectProperty(
|
|
3671
|
-
types.identifier('destination'),
|
|
3672
|
-
types.stringLiteral(
|
|
3673
|
-
typeof filter.destination === 'string' ? filter.destination : ''
|
|
3674
|
-
)
|
|
3675
|
-
),
|
|
3676
|
-
types.objectProperty(
|
|
3677
|
-
types.identifier('operand'),
|
|
3678
|
-
types.stringLiteral(filter.operand || '')
|
|
3679
|
-
),
|
|
3680
|
-
])
|
|
3681
|
-
)
|
|
3682
|
-
),
|
|
3683
|
-
]
|
|
3684
|
-
)
|
|
3776
|
+
buildStaticFiltersStringifyCall(staticFilters)
|
|
3685
3777
|
)
|
|
3686
3778
|
)
|
|
3687
3779
|
}
|
|
@@ -3766,9 +3858,7 @@ function updateGetStaticProps(
|
|
|
3766
3858
|
const maxPagesPropName = `${vars.propsPrefix}_maxPages`
|
|
3767
3859
|
// Use filter-specific count variable if usage has static filters
|
|
3768
3860
|
// (dynamic filters can't be resolved at build time)
|
|
3769
|
-
const staticFiltersForCount = (usage
|
|
3770
|
-
(f: any) => !ASTUtils.isUIDLDynamicReference(f.destination)
|
|
3771
|
-
)
|
|
3861
|
+
const staticFiltersForCount = staticFiltersOf(usage)
|
|
3772
3862
|
// A count scoped to an inner array is a different number from the
|
|
3773
3863
|
// whole-payload one, so it gets its own variable just like a filtered one.
|
|
3774
3864
|
const hasScopedCount = staticFiltersForCount.length > 0 || !!usage.itemsPath
|
|
@@ -3854,9 +3944,7 @@ function updateGetStaticProps(
|
|
|
3854
3944
|
usagesByFilters.forEach((usages, filtersKey) => {
|
|
3855
3945
|
const firstUsage = usages[0]
|
|
3856
3946
|
// Filter out dynamic destinations for getStaticProps (they can't be resolved at build time)
|
|
3857
|
-
const staticFiltersForCount = (firstUsage
|
|
3858
|
-
(f: any) => !ASTUtils.isUIDLDynamicReference(f.destination)
|
|
3859
|
-
)
|
|
3947
|
+
const staticFiltersForCount = staticFiltersOf(firstUsage)
|
|
3860
3948
|
const hasStaticFilters = staticFiltersForCount.length > 0
|
|
3861
3949
|
|
|
3862
3950
|
// Create unique count variable name based on filters (and inner-array
|
|
@@ -3887,31 +3975,7 @@ function updateGetStaticProps(
|
|
|
3887
3975
|
countParams.push(
|
|
3888
3976
|
types.objectProperty(
|
|
3889
3977
|
types.identifier('filters'),
|
|
3890
|
-
|
|
3891
|
-
types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
|
|
3892
|
-
[
|
|
3893
|
-
types.arrayExpression(
|
|
3894
|
-
staticFiltersForCount.map((f: any) =>
|
|
3895
|
-
types.objectExpression([
|
|
3896
|
-
types.objectProperty(
|
|
3897
|
-
types.identifier('source'),
|
|
3898
|
-
types.stringLiteral(f.source || '')
|
|
3899
|
-
),
|
|
3900
|
-
types.objectProperty(
|
|
3901
|
-
types.identifier('destination'),
|
|
3902
|
-
types.stringLiteral(
|
|
3903
|
-
typeof f.destination === 'string' ? f.destination : ''
|
|
3904
|
-
)
|
|
3905
|
-
),
|
|
3906
|
-
types.objectProperty(
|
|
3907
|
-
types.identifier('operand'),
|
|
3908
|
-
types.stringLiteral(f.operand || '')
|
|
3909
|
-
),
|
|
3910
|
-
])
|
|
3911
|
-
)
|
|
3912
|
-
),
|
|
3913
|
-
]
|
|
3914
|
-
)
|
|
3978
|
+
buildStaticFiltersStringifyCall(staticFiltersForCount)
|
|
3915
3979
|
)
|
|
3916
3980
|
)
|
|
3917
3981
|
}
|