@teleporthq/teleport-plugin-next-data-source 0.44.0 → 0.44.4
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/first-page-runtime.ts +184 -0
- package/__tests__/_helpers/pagination-widget-fixture.ts +67 -1
- package/__tests__/browser-row-policy.test.ts +202 -2
- package/__tests__/data-source-request-locale.test.ts +4 -3
- package/__tests__/fetchers.test.ts +6 -2
- package/__tests__/infinite-scroll.test.ts +210 -5
- package/__tests__/page-data-visitor-read.test.ts +196 -0
- package/__tests__/plain-list-sort.test.ts +1 -1
- package/__tests__/plain-list-starting-sort.test.ts +323 -0
- package/__tests__/refetch-loading-state.test.ts +158 -2
- package/__tests__/starting-sort-first-page.test.ts +285 -0
- package/dist/cjs/cache/ast.d.ts +2 -0
- package/dist/cjs/cache/ast.d.ts.map +1 -1
- package/dist/cjs/cache/ast.js +5 -2
- package/dist/cjs/cache/ast.js.map +1 -1
- package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
- package/dist/cjs/data-source-fetchers.js +10 -2
- package/dist/cjs/data-source-fetchers.js.map +1 -1
- package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
- package/dist/cjs/fetchers/teleport.js +1 -1
- package/dist/cjs/fetchers/teleport.js.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.d.ts.map +1 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.js +5 -1
- package/dist/cjs/fetchers/utils/browser-row-policy.js.map +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +14 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/infinite-scroll.d.ts +64 -2
- package/dist/cjs/infinite-scroll.d.ts.map +1 -1
- package/dist/cjs/infinite-scroll.js +102 -3
- package/dist/cjs/infinite-scroll.js.map +1 -1
- package/dist/cjs/loading-state.d.ts +23 -2
- package/dist/cjs/loading-state.d.ts.map +1 -1
- package/dist/cjs/loading-state.js +50 -15
- package/dist/cjs/loading-state.js.map +1 -1
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +200 -64
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/sort-utils.d.ts +53 -1
- package/dist/cjs/sort-utils.d.ts.map +1 -1
- package/dist/cjs/sort-utils.js +105 -13
- package/dist/cjs/sort-utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +3 -2
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +48 -18
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/cache/ast.d.ts +2 -0
- package/dist/esm/cache/ast.d.ts.map +1 -1
- package/dist/esm/cache/ast.js +3 -1
- package/dist/esm/cache/ast.js.map +1 -1
- package/dist/esm/data-source-fetchers.d.ts.map +1 -1
- package/dist/esm/data-source-fetchers.js +10 -2
- package/dist/esm/data-source-fetchers.js.map +1 -1
- package/dist/esm/fetchers/teleport.d.ts.map +1 -1
- package/dist/esm/fetchers/teleport.js +1 -1
- package/dist/esm/fetchers/teleport.js.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.d.ts.map +1 -1
- package/dist/esm/fetchers/utils/browser-row-policy.js +6 -2
- package/dist/esm/fetchers/utils/browser-row-policy.js.map +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +14 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/infinite-scroll.d.ts +64 -2
- package/dist/esm/infinite-scroll.d.ts.map +1 -1
- package/dist/esm/infinite-scroll.js +97 -2
- package/dist/esm/infinite-scroll.js.map +1 -1
- package/dist/esm/loading-state.d.ts +23 -2
- package/dist/esm/loading-state.d.ts.map +1 -1
- package/dist/esm/loading-state.js +50 -15
- package/dist/esm/loading-state.js.map +1 -1
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +204 -68
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/sort-utils.d.ts +53 -1
- package/dist/esm/sort-utils.d.ts.map +1 -1
- package/dist/esm/sort-utils.js +100 -12
- package/dist/esm/sort-utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +3 -2
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +49 -19
- package/dist/esm/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/cache/ast.ts +4 -1
- package/src/data-source-fetchers.ts +33 -14
- package/src/fetchers/teleport.ts +8 -2
- package/src/fetchers/utils/browser-row-policy.ts +79 -5
- package/src/index.ts +8 -2
- package/src/infinite-scroll.ts +182 -4
- package/src/loading-state.ts +85 -13
- package/src/pagination-plugin.ts +369 -83
- package/src/sort-utils.ts +164 -21
- package/src/utils.ts +55 -18
|
@@ -47,24 +47,24 @@ import { ChunkType, FileType, } from '@teleporthq/teleport-types';
|
|
|
47
47
|
import * as types from '@babel/types';
|
|
48
48
|
import { parseExpression } from '@babel/parser';
|
|
49
49
|
import { ASTStatementOrder, GenericUtils, StringUtils } from '@teleporthq/teleport-shared';
|
|
50
|
-
import { ASTUtils, URLQueryWriter, URLSearchParamSync } from '@teleporthq/teleport-plugin-common';
|
|
50
|
+
import { ASTUtils, RouteUtils, URLQueryWriter, URLSearchParamSync, } from '@teleporthq/teleport-plugin-common';
|
|
51
51
|
import { collectFilterLeafConditions, generateSafeFileName, pruneFilterTree } from './utils';
|
|
52
52
|
import { generateDataSourceFetcherWithCore } from './data-source-fetchers';
|
|
53
53
|
import { buildProductTransformOptions } from './transformations';
|
|
54
|
-
import { appendSortsParam,
|
|
54
|
+
import { appendSortsParam, buildSortAtStartGuard, buildStartingSortsValue, readRepeaterSort, } from './sort-utils';
|
|
55
55
|
import { appendFiltersParam, buildStaticFiltersStringifyCall, pushStateIdsAsDeps, pushPropIdsAsDeps, } from './filter-utils';
|
|
56
56
|
import { appendItemsPathParam, extractItemsPath } from './items-path';
|
|
57
57
|
import { resolveRepeaterPerPage } from './repeater-page-size';
|
|
58
58
|
import { applyLoadingStateToDataProvider, buildLoadingStateDeclarations, getLoadingStateVars, } from './loading-state';
|
|
59
59
|
import { mergeServerCacheOptions, resolveCacheFromRepeaterContent } from './cache/config';
|
|
60
|
-
import { buildCacheHydrationEffect, buildCacheStoreThen, buildCachedFetchBody, buildCachedParamsDeclarations, registerCacheClientImports, } from './cache/ast';
|
|
60
|
+
import { buildCacheHydrationEffect, buildCacheStoreThen, buildCachedFetchBody, buildCachedParamsDeclarations, paramsVarFor, registerCacheClientImports, } from './cache/ast';
|
|
61
61
|
import { convertControlToButton, dropInactivePaginationControls, findAllPaginationControls, findPaginationControl, PAGINATION_FOR_ATTR, readJSXAttributeString, setJSXExpressionAttribute, } from './pagination-controls';
|
|
62
62
|
import { findRangeControls, wireRangeControl } from './range-control';
|
|
63
63
|
import { findAllSearchInputsInJSX, pairSearchInputs, wireSearchInput } from './search-input';
|
|
64
64
|
import { buildCountFetchEffect, buildCountSeqDeclaration } from './count-effect';
|
|
65
65
|
import { findAllSearchClearButtonsInJSX, findSiblingSearchInput, wireSearchClearButton, } from './search-clear';
|
|
66
66
|
import { buildPageTokensDeclaration, wireNumberedPagination, } from './numbered-pagination';
|
|
67
|
-
import { buildAccumulatingRequestMark, buildAccumulatingResponseHandler, buildInfiniteScrollDeclarations, buildSentinelElement, buildSentinelObserverEffect, getInfiniteScrollVars, } from './infinite-scroll';
|
|
67
|
+
import { buildAccumulatingRequestMark, buildAccumulatingResponseHandler, buildAppendingRequestCheck, buildFirstPageDeclaration, buildFirstPageSeedEffect, buildInfiniteScrollDeclarations, buildSentinelElement, buildSentinelObserverEffect, buildServerRowsExpression, getInfiniteScrollVars, } from './infinite-scroll';
|
|
68
68
|
import { buildFilterSortPageResetEffect, buildPageResetRefDeclaration, hasNoPageResetDeps, } from './page-reset';
|
|
69
69
|
import { buildPageUrlRefDeclaration, buildPageUrlSyncEffect } from './page-url-sync';
|
|
70
70
|
import { isLocalizedProject } from './content-localization';
|
|
@@ -275,7 +275,7 @@ function buildFilterDestinationExpression(destination) {
|
|
|
275
275
|
return ASTUtils.convertFilterDestinationToExpression(destination);
|
|
276
276
|
}
|
|
277
277
|
// Scan UIDL to find all data source usages and build a registry
|
|
278
|
-
function buildStateRegistry(uidlNode) {
|
|
278
|
+
function buildStateRegistry(uidlNode, stateDefinitions) {
|
|
279
279
|
var usages = [];
|
|
280
280
|
var byDataSourceId = new Map();
|
|
281
281
|
var byArrayMapperRenderProp = new Map();
|
|
@@ -332,16 +332,19 @@ function buildStateRegistry(uidlNode) {
|
|
|
332
332
|
// is skipped for a dynamic sort) — the pre-rendered HTML carried no
|
|
333
333
|
// posts, and the browser fetched page 1 a second time. Only a sort
|
|
334
334
|
// bound to state (the admin panel's sortable columns) is dynamic.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
335
|
+
//
|
|
336
|
+
// A sort the visitor picks still starts somewhere — the store's sort
|
|
337
|
+
// dropdown at "Name A-Z". Known at build time, it orders the
|
|
338
|
+
// server-side first page, which the list then shows while the visitor
|
|
339
|
+
// leaves the sort alone. Read as a plain list's page fetch reads it.
|
|
340
|
+
var repeaterSort = !sorts || sorts.length === 0
|
|
341
|
+
? readRepeaterSort(content.sort, content.sortDirection, stateDefinitions)
|
|
342
|
+
: {};
|
|
343
|
+
if (repeaterSort.fixed) {
|
|
344
|
+
sorts = [repeaterSort.fixed];
|
|
344
345
|
}
|
|
346
|
+
var dynamicSort = repeaterSort.dynamic;
|
|
347
|
+
var startingSort = repeaterSort.starting;
|
|
345
348
|
// Extract filters from parent's resource params, keeping the group tree
|
|
346
349
|
// the inspector authored (see `readFilterTree`).
|
|
347
350
|
var filters = [];
|
|
@@ -424,6 +427,7 @@ function buildStateRegistry(uidlNode) {
|
|
|
424
427
|
queryColumns: queryColumns,
|
|
425
428
|
sorts: sorts,
|
|
426
429
|
dynamicSort: dynamicSort,
|
|
430
|
+
startingSort: startingSort,
|
|
427
431
|
filters: filters,
|
|
428
432
|
filterStateIds: filterStateIds,
|
|
429
433
|
filterPropIds: filterPropIds,
|
|
@@ -780,7 +784,7 @@ function pushFilterSortPageResetEffect(stateDeclarations, effectStatements, usag
|
|
|
780
784
|
// ==================== MAIN PLUGIN ====================
|
|
781
785
|
export var createNextArrayMapperPaginationPlugin = function () {
|
|
782
786
|
var paginationPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () {
|
|
783
|
-
var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, rangeControls, hasRangeControl, registry, getStaticPropsChunk, isPage, localized, stateDeclarations, effectStatements, needsUseRouter, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, loadingStateDeclarations, usagesWithLoadingState, usageByProviderNode, cacheDeclarations, sharedOptions, cachedScopes, dataProvidersWithoutRepeaters, searchInputs, usageBySearchInput, _i, searchInputs_1, input, usage;
|
|
787
|
+
var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, rangeControls, hasRangeControl, registry, getStaticPropsChunk, isPage, localized, stateDeclarations, effectStatements, needsUseRouter, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, loadingStateDeclarations, usagesWithLoadingState, usageByProviderNode, cacheDeclarations, firstPageDeclarations, sharedOptions, cachedScopes, dataProvidersWithoutRepeaters, searchInputs, usageBySearchInput, _i, searchInputs_1, input, usage;
|
|
784
788
|
var _a, _b;
|
|
785
789
|
return __generator(this, function (_c) {
|
|
786
790
|
uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options;
|
|
@@ -806,7 +810,7 @@ export var createNextArrayMapperPaginationPlugin = function () {
|
|
|
806
810
|
blockStatement = arrowFunction.body;
|
|
807
811
|
rangeControls = findRangeControls(blockStatement);
|
|
808
812
|
hasRangeControl = rangeControls.length > 0;
|
|
809
|
-
registry = buildStateRegistry(uidl.node);
|
|
813
|
+
registry = buildStateRegistry(uidl.node, uidl.stateDefinitions);
|
|
810
814
|
if (registry.usages.length === 0) {
|
|
811
815
|
return [2 /*return*/, structure];
|
|
812
816
|
}
|
|
@@ -1141,6 +1145,7 @@ export var createNextArrayMapperPaginationPlugin = function () {
|
|
|
1141
1145
|
usagesWithLoadingState = new Set();
|
|
1142
1146
|
usageByProviderNode = new Map();
|
|
1143
1147
|
cacheDeclarations = [];
|
|
1148
|
+
firstPageDeclarations = isPage ? [] : undefined;
|
|
1144
1149
|
dataProvidersWithRepeaters.forEach(function (dp) {
|
|
1145
1150
|
var _a, _b;
|
|
1146
1151
|
var nameAttr = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
|
|
@@ -1161,10 +1166,10 @@ export var createNextArrayMapperPaginationPlugin = function () {
|
|
|
1161
1166
|
var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
|
|
1162
1167
|
// Update DataProvider based on category
|
|
1163
1168
|
if (usage.category === 'paginated+search') {
|
|
1164
|
-
updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations, localized);
|
|
1169
|
+
updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations, localized, firstPageDeclarations);
|
|
1165
1170
|
}
|
|
1166
1171
|
else if (usage.category === 'paginated-only') {
|
|
1167
|
-
updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations, localized);
|
|
1172
|
+
updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations, localized, firstPageDeclarations);
|
|
1168
1173
|
}
|
|
1169
1174
|
else if (usage.category === 'search-only') {
|
|
1170
1175
|
updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclarations, localized);
|
|
@@ -1176,9 +1181,14 @@ export var createNextArrayMapperPaginationPlugin = function () {
|
|
|
1176
1181
|
// change refetches, instead of leaving the previous rows on screen with
|
|
1177
1182
|
// no feedback. Runs last so it sees the `fetchData` and
|
|
1178
1183
|
// `persistDataDuringLoading` attributes the updaters above just wrote.
|
|
1184
|
+
// An appending list keeps its rows on screen while its next page loads;
|
|
1185
|
+
// only a list loading afresh falls through to the loading slot.
|
|
1179
1186
|
var loadingVars = getLoadingStateVars(usage.index);
|
|
1180
|
-
|
|
1181
|
-
|
|
1187
|
+
var appendingRequest = usage.infiniteScroll && usage.paginated
|
|
1188
|
+
? buildAppendingRequestCheck(getInfiniteScrollVars(usage.index))
|
|
1189
|
+
: undefined;
|
|
1190
|
+
if (applyLoadingStateToDataProvider(dp, loadingVars, appendingRequest)) {
|
|
1191
|
+
loadingStateDeclarations.push.apply(loadingStateDeclarations, buildLoadingStateDeclarations(loadingVars, !!appendingRequest));
|
|
1182
1192
|
// Recorded because the loading state is only declared for a provider
|
|
1183
1193
|
// that HAS a loading slot; a Load More button wired later may only
|
|
1184
1194
|
// reference `ds_N_isFetching` if it actually exists.
|
|
@@ -1223,6 +1233,11 @@ export var createNextArrayMapperPaginationPlugin = function () {
|
|
|
1223
1233
|
ASTStatementOrder.insertStatementsAfterDependencies(blockStatement, cacheDeclarations);
|
|
1224
1234
|
registerCacheClientImports(dependencies, (_a = uidl.outputOptions) === null || _a === void 0 ? void 0 : _a.folderPath);
|
|
1225
1235
|
}
|
|
1236
|
+
// After the cache declarations: a cached list's first page reads the
|
|
1237
|
+
// `ds_N_params` they hoisted.
|
|
1238
|
+
if (firstPageDeclarations === null || firstPageDeclarations === void 0 ? void 0 : firstPageDeclarations.length) {
|
|
1239
|
+
ASTStatementOrder.insertStatementsAfterDependencies(blockStatement, firstPageDeclarations);
|
|
1240
|
+
}
|
|
1226
1241
|
dataProvidersWithoutRepeaters = dataProviders.filter(function (dp) {
|
|
1227
1242
|
var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
|
|
1228
1243
|
return !hasRepeater;
|
|
@@ -1283,9 +1298,11 @@ export var createNextArrayMapperPaginationPlugin = function () {
|
|
|
1283
1298
|
wireRangeControlFor(control, owner, getStateVarsForUsage(owner));
|
|
1284
1299
|
}
|
|
1285
1300
|
});
|
|
1286
|
-
// STEP 6: Update getStaticProps if this is a page
|
|
1301
|
+
// STEP 6: Update getStaticProps if this is a page. Its rows are what the
|
|
1302
|
+
// page renders, so they are read as a visitor is served them — unless only
|
|
1303
|
+
// the store's trusted readers can open the page (`pageDataReadArguments`).
|
|
1287
1304
|
if (isPage) {
|
|
1288
|
-
updateGetStaticProps(chunks, registry, dependencies, (_b = uidl.outputOptions) === null || _b === void 0 ? void 0 : _b.folderPath, localized);
|
|
1305
|
+
updateGetStaticProps(chunks, registry, dependencies, (_b = uidl.outputOptions) === null || _b === void 0 ? void 0 : _b.folderPath, localized, function () { return RouteUtils.pageDataReadArguments(uidl, options.auth); });
|
|
1289
1306
|
}
|
|
1290
1307
|
return [2 /*return*/, structure];
|
|
1291
1308
|
});
|
|
@@ -1544,34 +1561,97 @@ function findPaginationNodesWithOwners(blockStatement, usageByProviderNode) {
|
|
|
1544
1561
|
*
|
|
1545
1562
|
* An uncached mapper keeps the inline `params={useMemo(...)}` it has always had,
|
|
1546
1563
|
* byte for byte. A cached one hoists that memo into a component const so the
|
|
1547
|
-
* peek can depend on the same object identity instead of rebuilding it
|
|
1564
|
+
* peek can depend on the same object identity instead of rebuilding it; so does
|
|
1565
|
+
* an appending list that starts from its page's rows (`hoistInto`), whose first
|
|
1566
|
+
* page is filed in the accumulator under those params.
|
|
1548
1567
|
*
|
|
1549
|
-
* Returns the identifier holding the
|
|
1550
|
-
*
|
|
1568
|
+
* Returns the identifier holding the params when they were hoisted, and the one
|
|
1569
|
+
* holding the peeked rows when this mapper caches.
|
|
1551
1570
|
*/
|
|
1552
1571
|
function pushParamsAttribute(
|
|
1553
1572
|
// tslint:disable-next-line:no-any
|
|
1554
|
-
dp, usage, paramsProps, memoDeps, cacheDeclarations) {
|
|
1573
|
+
dp, usage, paramsProps, memoDeps, cacheDeclarations, hoistInto) {
|
|
1555
1574
|
var _a;
|
|
1556
1575
|
var paramsMemo = types.callExpression(types.identifier('useMemo'), [
|
|
1557
1576
|
types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
|
|
1558
1577
|
types.arrayExpression(memoDeps),
|
|
1559
1578
|
]);
|
|
1560
|
-
// A state-bound sort
|
|
1561
|
-
//
|
|
1562
|
-
//
|
|
1563
|
-
//
|
|
1579
|
+
// A state-bound sort gets no cache peek. The peek is `initialData` by another
|
|
1580
|
+
// name, and such a list takes the server's rows only while its sort is still
|
|
1581
|
+
// where the visitor starts (`buildStartingSortGuard`); the peek was never
|
|
1582
|
+
// extended to it.
|
|
1564
1583
|
var cache = ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) && !usage.dynamicSort ? usage.cache : undefined;
|
|
1565
1584
|
if (!cache) {
|
|
1566
|
-
|
|
1567
|
-
|
|
1585
|
+
if (!hoistInto) {
|
|
1586
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(paramsMemo)));
|
|
1587
|
+
return {};
|
|
1588
|
+
}
|
|
1589
|
+
var paramsIdentifier = paramsVarFor(usage.index);
|
|
1590
|
+
hoistInto.push(types.variableDeclaration('const', [
|
|
1591
|
+
types.variableDeclarator(types.identifier(paramsIdentifier), paramsMemo),
|
|
1592
|
+
]));
|
|
1593
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.identifier(paramsIdentifier))));
|
|
1594
|
+
return { paramsIdentifier: paramsIdentifier };
|
|
1568
1595
|
}
|
|
1569
1596
|
var hoisted = buildCachedParamsDeclarations({ index: usage.index, paramsMemo: paramsMemo, cache: cache });
|
|
1570
1597
|
cacheDeclarations.push.apply(cacheDeclarations, hoisted.declarations);
|
|
1571
1598
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.identifier(hoisted.paramsIdentifier))));
|
|
1572
|
-
return hoisted.cachedIdentifier;
|
|
1599
|
+
return { paramsIdentifier: hoisted.paramsIdentifier, cachedIdentifier: hoisted.cachedIdentifier };
|
|
1600
|
+
}
|
|
1601
|
+
// Whether the rows `getStaticProps` fetched can be this list's first page at
|
|
1602
|
+
// all. A sort bound to state can only be served them when the build knows the
|
|
1603
|
+
// sort the visitor starts with (`startingSort`) and fetched by it; otherwise
|
|
1604
|
+
// the fetch has no sort, and its rows are not the list's first page.
|
|
1605
|
+
function prefetchFollowsSort(usage) {
|
|
1606
|
+
return !usage.dynamicSort || !!usage.startingSort;
|
|
1607
|
+
}
|
|
1608
|
+
// `sortBy === "name-asc"`: the visitor has not moved the sort from where it
|
|
1609
|
+
// starts, so the build-time rows are still its first page. `null` for a list
|
|
1610
|
+
// whose sort the visitor cannot pick, or one that reads no state.
|
|
1611
|
+
function buildStartingSortGuard(usage) {
|
|
1612
|
+
return usage.dynamicSort && usage.startingSort ? buildSortAtStartGuard(usage.startingSort) : null;
|
|
1613
|
+
}
|
|
1614
|
+
// `<condition> && <starting-sort guard>`, or the condition alone.
|
|
1615
|
+
function withStartingSortGuard(condition, usage) {
|
|
1616
|
+
var sortGuard = buildStartingSortGuard(usage);
|
|
1617
|
+
return sortGuard ? types.logicalExpression('&&', condition, sortGuard) : condition;
|
|
1618
|
+
}
|
|
1619
|
+
// An appending list on a page starts from the rows its `getStaticProps`
|
|
1620
|
+
// fetched, when they can be its first page (`prefetchFollowsSort`).
|
|
1621
|
+
function startsFromServerRows(usage) {
|
|
1622
|
+
return usage.infiniteScroll && usage.paginated && prefetchFollowsSort(usage);
|
|
1573
1623
|
}
|
|
1574
|
-
|
|
1624
|
+
/**
|
|
1625
|
+
* `initialData={ds_N_firstPage}` on an appending list, beside the frozen first
|
|
1626
|
+
* page and the effect that files it as page 1 of the accumulator (see
|
|
1627
|
+
* `infinite-scroll.ts`).
|
|
1628
|
+
*
|
|
1629
|
+
* The rows stand in for page 1 only while they answer the list's query: no
|
|
1630
|
+
* search (`queryGuard`), the sort where the visitor starts, no filter set (the
|
|
1631
|
+
* guards the paged lists use), and at least one row — an empty build-time
|
|
1632
|
+
* answer, which a failed fetch also gives, leaves the browser to fetch page 1
|
|
1633
|
+
* as before.
|
|
1634
|
+
*/
|
|
1635
|
+
function pushInfiniteScrollFirstPage(
|
|
1636
|
+
// tslint:disable-next-line:no-any
|
|
1637
|
+
dp, usage, vars, paramsIdentifier, declarations, queryGuard, instanceDeps) {
|
|
1638
|
+
var infiniteVars = getInfiniteScrollVars(usage.index);
|
|
1639
|
+
var serverPayload = function () {
|
|
1640
|
+
return types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true);
|
|
1641
|
+
};
|
|
1642
|
+
var hasServerRows = types.binaryExpression('>', types.optionalMemberExpression(buildServerRowsExpression(serverPayload(), usage.itemsPath), types.identifier('length'), false, true), types.numericLiteral(0));
|
|
1643
|
+
var startsFromServer = [
|
|
1644
|
+
queryGuard,
|
|
1645
|
+
buildStartingSortGuard(usage),
|
|
1646
|
+
buildNoUrlFilterGuard(usage),
|
|
1647
|
+
hasServerRows,
|
|
1648
|
+
]
|
|
1649
|
+
.filter(function (guard) { return guard !== null; })
|
|
1650
|
+
.reduce(function (all, guard) { return types.logicalExpression('&&', all, guard); });
|
|
1651
|
+
declarations.push(buildFirstPageDeclaration(infiniteVars, startsFromServer, serverPayload(), instanceDeps), buildFirstPageSeedEffect(infiniteVars, paramsIdentifier, usage.perPage, usage.itemsPath));
|
|
1652
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.identifier(infiniteVars.firstPageVar))));
|
|
1653
|
+
}
|
|
1654
|
+
function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations, localized, firstPageDeclarations) {
|
|
1575
1655
|
var attrs = dp.openingElement.attributes;
|
|
1576
1656
|
// Remove existing params, key, initialData, fetchData, persistDataDuringLoading
|
|
1577
1657
|
dp.openingElement.attributes = attrs.filter(function (attr) {
|
|
@@ -1604,20 +1684,29 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDe
|
|
|
1604
1684
|
if (localized) {
|
|
1605
1685
|
appendClientLocaleParam(paramsProps, memoDeps);
|
|
1606
1686
|
}
|
|
1607
|
-
var
|
|
1608
|
-
|
|
1609
|
-
//
|
|
1610
|
-
//
|
|
1611
|
-
// the
|
|
1612
|
-
//
|
|
1613
|
-
//
|
|
1687
|
+
var seedInto = startsFromServerRows(usage) ? firstPageDeclarations : undefined;
|
|
1688
|
+
var _a = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations, seedInto), paramsIdentifier = _a.paramsIdentifier, cachedInitialData = _a.cachedIdentifier;
|
|
1689
|
+
// Add initialData: the server-prefetched page 1 while it is the page on show
|
|
1690
|
+
// — page 1, no search, no filter set, and a sort the visitor picks still where
|
|
1691
|
+
// they start (the prefetch ran by that sort). A list whose starting sort the
|
|
1692
|
+
// build cannot know never takes it: that prefetch ran without a sort, so
|
|
1693
|
+
// reusing it would mask the current sort AND make DataProvider skip its first
|
|
1694
|
+
// client fetch (its internal guard only skips when initialData is defined on
|
|
1695
|
+
// mount). Any other sort is fetched fresh, through the useMemo params.
|
|
1614
1696
|
//
|
|
1615
|
-
// An appending list
|
|
1616
|
-
//
|
|
1617
|
-
//
|
|
1618
|
-
//
|
|
1619
|
-
|
|
1620
|
-
|
|
1697
|
+
// An appending list takes its own: `initialData` makes DataProvider skip its
|
|
1698
|
+
// first fetch, so the prefetched page 1 has to be filed in the accumulator
|
|
1699
|
+
// too, or appending page 2 would REPLACE the visible rows with page 2 alone.
|
|
1700
|
+
// The provider remounts per query (its `key`), so the first page is frozen
|
|
1701
|
+
// per query.
|
|
1702
|
+
if (seedInto && paramsIdentifier) {
|
|
1703
|
+
var appliedQuery = function () {
|
|
1704
|
+
return types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery'));
|
|
1705
|
+
};
|
|
1706
|
+
pushInfiniteScrollFirstPage(dp, usage, vars, paramsIdentifier, seedInto, types.unaryExpression('!', appliedQuery(), true), [appliedQuery()]);
|
|
1707
|
+
}
|
|
1708
|
+
else if (prefetchFollowsSort(usage) && !usage.infiniteScroll) {
|
|
1709
|
+
var initialDataCondition = wrapInitialDataWithUrlFilterGuard(withStartingSortGuard(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)), usage), usage);
|
|
1621
1710
|
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), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
|
|
1622
1711
|
}
|
|
1623
1712
|
// Add key. Sort is intentionally NOT part of the key — a key change would
|
|
@@ -1655,7 +1744,7 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDe
|
|
|
1655
1744
|
// Add persistDataDuringLoading
|
|
1656
1745
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
|
|
1657
1746
|
}
|
|
1658
|
-
function updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations, localized) {
|
|
1747
|
+
function updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations, localized, firstPageDeclarations) {
|
|
1659
1748
|
var attrs = dp.openingElement.attributes;
|
|
1660
1749
|
dp.openingElement.attributes = attrs.filter(function (attr) {
|
|
1661
1750
|
var _a;
|
|
@@ -1684,12 +1773,17 @@ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDec
|
|
|
1684
1773
|
appendClientLocaleParam(paramsProps, memoDeps);
|
|
1685
1774
|
}
|
|
1686
1775
|
// Add params
|
|
1687
|
-
var
|
|
1688
|
-
|
|
1689
|
-
//
|
|
1690
|
-
//
|
|
1691
|
-
|
|
1692
|
-
|
|
1776
|
+
var seedInto = startsFromServerRows(usage) ? firstPageDeclarations : undefined;
|
|
1777
|
+
var _a = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations, seedInto), paramsIdentifier = _a.paramsIdentifier, cachedInitialData = _a.cachedIdentifier;
|
|
1778
|
+
// Add initialData. See paginated+search updater for when a sort the visitor
|
|
1779
|
+
// picks may reuse the prefetch, and how an appending list takes its own. This
|
|
1780
|
+
// provider never remounts (no `key`), so its first page is frozen for the
|
|
1781
|
+
// page's lifetime.
|
|
1782
|
+
if (seedInto && paramsIdentifier) {
|
|
1783
|
+
pushInfiniteScrollFirstPage(dp, usage, vars, paramsIdentifier, seedInto, null, []);
|
|
1784
|
+
}
|
|
1785
|
+
else if (prefetchFollowsSort(usage) && !usage.infiniteScroll) {
|
|
1786
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(withStartingSortGuard(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), usage), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
|
|
1693
1787
|
}
|
|
1694
1788
|
// Add key — sort is intentionally NOT included; see paginated+search updater,
|
|
1695
1789
|
// which also explains why an appending list keys on nothing at all (there is
|
|
@@ -1739,11 +1833,11 @@ function updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclara
|
|
|
1739
1833
|
if (localized) {
|
|
1740
1834
|
appendClientLocaleParam(paramsProps, memoDeps);
|
|
1741
1835
|
}
|
|
1742
|
-
var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
|
|
1743
|
-
// Add initialData. See paginated+search updater for
|
|
1744
|
-
//
|
|
1745
|
-
if (
|
|
1746
|
-
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.unaryExpression('!', types.identifier(vars.debouncedSearchQueryVar), true), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
|
|
1836
|
+
var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations).cachedIdentifier;
|
|
1837
|
+
// Add initialData. See paginated+search updater for when a sort the visitor
|
|
1838
|
+
// picks may reuse the prefetch.
|
|
1839
|
+
if (prefetchFollowsSort(usage)) {
|
|
1840
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(withStartingSortGuard(types.unaryExpression('!', types.identifier(vars.debouncedSearchQueryVar), true), usage), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
|
|
1747
1841
|
}
|
|
1748
1842
|
// Add key — sort is intentionally NOT included; see paginated+search updater.
|
|
1749
1843
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
|
|
@@ -1754,14 +1848,42 @@ function updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclara
|
|
|
1754
1848
|
dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
|
|
1755
1849
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
|
|
1756
1850
|
}
|
|
1851
|
+
/**
|
|
1852
|
+
* A plain list on a page is seeded with the rows its `getStaticProps` fetched
|
|
1853
|
+
* (`extractDataSourceIntoGetStaticProps`), and a seeded provider skips its first
|
|
1854
|
+
* fetch. With a sort the visitor picks, those rows are the list's only while the
|
|
1855
|
+
* sort is where a visitor starts — the build fetched them by it:
|
|
1856
|
+
*
|
|
1857
|
+
* initialData={sortBy === "name-asc" ? props.items_products : undefined}
|
|
1858
|
+
*
|
|
1859
|
+
* — and any other sort is fetched fresh, through the params it changes. When the
|
|
1860
|
+
* build cannot know where the sort starts (`prefetchFollowsSort`), it fetched
|
|
1861
|
+
* the rows unsorted, and the list is never seeded with them. A plain list has no
|
|
1862
|
+
* search, and is only seeded without a filter a visitor sets.
|
|
1863
|
+
*/
|
|
1864
|
+
function seedPlainListWhileSortStarts(dp, usage) {
|
|
1865
|
+
if (!usage.dynamicSort) {
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
var attrs = dp.openingElement.attributes;
|
|
1869
|
+
var index = attrs.findIndex(function (attr) { var _a; return attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === 'initialData'; });
|
|
1870
|
+
if (index === -1) {
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
if (!prefetchFollowsSort(usage)) {
|
|
1874
|
+
attrs.splice(index, 1);
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
var sortGuard = buildStartingSortGuard(usage);
|
|
1878
|
+
var seeded = attrs[index].value;
|
|
1879
|
+
if (!sortGuard || (seeded === null || seeded === void 0 ? void 0 : seeded.type) !== 'JSXExpressionContainer') {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
attrs[index] = types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(sortGuard, seeded.expression, types.identifier('undefined'))));
|
|
1883
|
+
}
|
|
1757
1884
|
function updateDataProviderForPlain(dp, fileName, usage, localized) {
|
|
1758
1885
|
var _a, _b, _c, _d, _e, _f;
|
|
1759
|
-
|
|
1760
|
-
// pre-rendered in the table's order would stand in for it, since a seeded
|
|
1761
|
-
// provider skips its first fetch — the paginated lists drop them the same way.
|
|
1762
|
-
if (usage.dynamicSort) {
|
|
1763
|
-
dp.openingElement.attributes = dp.openingElement.attributes.filter(function (attr) { var _a; return !(attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === 'initialData'); });
|
|
1764
|
-
}
|
|
1886
|
+
seedPlainListWhileSortStarts(dp, usage);
|
|
1765
1887
|
var attrs = dp.openingElement.attributes;
|
|
1766
1888
|
var clientCache = ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined;
|
|
1767
1889
|
// Check if fetchData already exists
|
|
@@ -2215,7 +2337,15 @@ function ensureAPIRouteExists(extractedResources, usage, dataSources, transformO
|
|
|
2215
2337
|
};
|
|
2216
2338
|
}
|
|
2217
2339
|
}
|
|
2218
|
-
|
|
2340
|
+
// `fetchCount(<params>, <read arguments>)`: the params may be left out only
|
|
2341
|
+
// when nothing follows them.
|
|
2342
|
+
var countReadArguments = function (countParams, readArguments) {
|
|
2343
|
+
return countParams.length > 0 || readArguments.length > 0
|
|
2344
|
+
? __spreadArray([types.objectExpression(countParams)], readArguments, true) : [];
|
|
2345
|
+
};
|
|
2346
|
+
function updateGetStaticProps(chunks, registry, dependencies, folderPath, localized,
|
|
2347
|
+
// The arguments every read hands the module after its params (fresh nodes per call).
|
|
2348
|
+
readArguments) {
|
|
2219
2349
|
var _a;
|
|
2220
2350
|
var getStaticPropsChunk = chunks.find(function (c) { return c.name === 'getStaticProps'; });
|
|
2221
2351
|
if (!getStaticPropsChunk || getStaticPropsChunk.type !== ChunkType.AST) {
|
|
@@ -2296,6 +2426,12 @@ function updateGetStaticProps(chunks, registry, dependencies, folderPath, locali
|
|
|
2296
2426
|
})),
|
|
2297
2427
|
])));
|
|
2298
2428
|
}
|
|
2429
|
+
else if (usage.dynamicSort && usage.startingSort) {
|
|
2430
|
+
// A sort the visitor picks: page 1 by the sort they start with, sent
|
|
2431
|
+
// as the very string the browser sends for it, so page 2 continues
|
|
2432
|
+
// this page exactly (see `buildStartingSortsValue`).
|
|
2433
|
+
fetchParams.push(types.objectProperty(types.identifier('sorts'), buildStartingSortsValue(usage.dynamicSort, usage.startingSort)));
|
|
2434
|
+
}
|
|
2299
2435
|
// Add filters if present
|
|
2300
2436
|
// Filter out dynamic destinations for getStaticProps (they can't be resolved at build time)
|
|
2301
2437
|
var staticFilters = staticFiltersOf(usage);
|
|
@@ -2311,7 +2447,7 @@ function updateGetStaticProps(chunks, registry, dependencies, folderPath, locali
|
|
|
2311
2447
|
var existingFetchIndex = arrayPattern.elements.findIndex(function (el) { return (el === null || el === void 0 ? void 0 : el.type) === 'Identifier' && el.name === vars.propsPrefix; });
|
|
2312
2448
|
if (existingFetchIndex === -1) {
|
|
2313
2449
|
arrayPattern.elements.push(types.identifier(vars.propsPrefix));
|
|
2314
|
-
fetchesArray.elements.push(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchData')), [types.objectExpression(fetchParams)]), types.identifier('catch')), [
|
|
2450
|
+
fetchesArray.elements.push(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchData')), __spreadArray([types.objectExpression(fetchParams)], readArguments(), true)), types.identifier('catch')), [
|
|
2315
2451
|
types.arrowFunctionExpression([types.identifier('error')], types.blockStatement([
|
|
2316
2452
|
types.expressionStatement(types.callExpression(types.memberExpression(types.identifier('console'), types.identifier('error')), [
|
|
2317
2453
|
types.stringLiteral("Error fetching ".concat(vars.propsPrefix, ":")),
|
|
@@ -2414,7 +2550,7 @@ function updateGetStaticProps(chunks, registry, dependencies, folderPath, locali
|
|
|
2414
2550
|
countParams.push(types.objectProperty(types.identifier('filters'), buildStaticFiltersStringifyCall(staticFiltersForCount)));
|
|
2415
2551
|
}
|
|
2416
2552
|
appendItemsPathParam(countParams, firstUsage.itemsPath, 'collectionPath');
|
|
2417
|
-
fetchesArray.elements.push(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchCount')), countParams
|
|
2553
|
+
fetchesArray.elements.push(types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchCount')), countReadArguments(countParams, readArguments())), types.identifier('catch')), [
|
|
2418
2554
|
types.arrowFunctionExpression([types.identifier('error')], types.blockStatement([
|
|
2419
2555
|
types.expressionStatement(types.callExpression(types.memberExpression(types.identifier('console'), types.identifier('error')), [
|
|
2420
2556
|
types.stringLiteral("Error fetching ".concat(countVarName, ":")),
|