@teleporthq/teleport-plugin-next-data-source 0.43.55 → 0.43.59
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__/array-mapper-cache-wiring.test.ts +425 -0
- package/__tests__/data-source-cache-wrapping.test.ts +152 -0
- package/__tests__/ecommerce-product-allow-backorders.test.ts +156 -0
- package/__tests__/ecommerce-product-model.test.ts +179 -0
- package/__tests__/ecommerce-product-storefront-tax.test.ts +118 -0
- package/dist/cjs/cache/ast.d.ts +71 -0
- package/dist/cjs/cache/ast.d.ts.map +1 -0
- package/dist/cjs/cache/ast.js +229 -0
- package/dist/cjs/cache/ast.js.map +1 -0
- package/dist/cjs/cache/config.d.ts +22 -0
- package/dist/cjs/cache/config.d.ts.map +1 -0
- package/dist/cjs/cache/config.js +67 -0
- package/dist/cjs/cache/config.js.map +1 -0
- package/dist/cjs/cache/types.d.ts +31 -0
- package/dist/cjs/cache/types.d.ts.map +1 -0
- package/dist/cjs/cache/types.js +3 -0
- package/dist/cjs/cache/types.js.map +1 -0
- package/dist/cjs/data-source-fetchers.d.ts +5 -3
- package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
- package/dist/cjs/data-source-fetchers.js +51 -8
- package/dist/cjs/data-source-fetchers.js.map +1 -1
- package/dist/cjs/fetchers/teleport.d.ts +2 -2
- package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
- package/dist/cjs/fetchers/teleport.js +3 -2
- package/dist/cjs/fetchers/teleport.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +14 -9
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/loading-state.d.ts.map +1 -1
- package/dist/cjs/loading-state.js +74 -2
- 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 +204 -64
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/transformations/ecommerce-product.d.ts +27 -1
- package/dist/cjs/transformations/ecommerce-product.d.ts.map +1 -1
- package/dist/cjs/transformations/ecommerce-product.js +8 -3
- package/dist/cjs/transformations/ecommerce-product.js.map +1 -1
- package/dist/cjs/transformations/index.d.ts +14 -2
- package/dist/cjs/transformations/index.d.ts.map +1 -1
- package/dist/cjs/transformations/index.js +37 -3
- package/dist/cjs/transformations/index.js.map +1 -1
- package/dist/cjs/transformations/shared-utils.d.ts.map +1 -1
- package/dist/cjs/transformations/shared-utils.js +1 -1
- package/dist/cjs/transformations/shared-utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +4 -3
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +6 -4
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/cache/ast.d.ts +71 -0
- package/dist/esm/cache/ast.d.ts.map +1 -0
- package/dist/esm/cache/ast.js +196 -0
- package/dist/esm/cache/ast.js.map +1 -0
- package/dist/esm/cache/config.d.ts +22 -0
- package/dist/esm/cache/config.d.ts.map +1 -0
- package/dist/esm/cache/config.js +62 -0
- package/dist/esm/cache/config.js.map +1 -0
- package/dist/esm/cache/types.d.ts +31 -0
- package/dist/esm/cache/types.d.ts.map +1 -0
- package/dist/esm/cache/types.js +2 -0
- package/dist/esm/cache/types.js.map +1 -0
- package/dist/esm/data-source-fetchers.d.ts +5 -3
- package/dist/esm/data-source-fetchers.d.ts.map +1 -1
- package/dist/esm/data-source-fetchers.js +51 -8
- package/dist/esm/data-source-fetchers.js.map +1 -1
- package/dist/esm/fetchers/teleport.d.ts +2 -2
- package/dist/esm/fetchers/teleport.d.ts.map +1 -1
- package/dist/esm/fetchers/teleport.js +3 -2
- package/dist/esm/fetchers/teleport.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +12 -8
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/loading-state.d.ts.map +1 -1
- package/dist/esm/loading-state.js +74 -2
- 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 +205 -65
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/transformations/ecommerce-product.d.ts +27 -1
- package/dist/esm/transformations/ecommerce-product.d.ts.map +1 -1
- package/dist/esm/transformations/ecommerce-product.js +8 -3
- package/dist/esm/transformations/ecommerce-product.js.map +1 -1
- package/dist/esm/transformations/index.d.ts +14 -2
- package/dist/esm/transformations/index.d.ts.map +1 -1
- package/dist/esm/transformations/index.js +36 -3
- package/dist/esm/transformations/index.js.map +1 -1
- package/dist/esm/transformations/shared-utils.d.ts.map +1 -1
- package/dist/esm/transformations/shared-utils.js +1 -1
- package/dist/esm/transformations/shared-utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +4 -3
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +6 -4
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/cache/ast.ts +265 -0
- package/src/cache/config.ts +79 -0
- package/src/cache/types.ts +31 -0
- package/src/data-source-fetchers.ts +66 -12
- package/src/fetchers/teleport.ts +3 -3
- package/src/index.ts +10 -4
- package/src/loading-state.ts +65 -2
- package/src/pagination-plugin.ts +315 -116
- package/src/transformations/ecommerce-product.ts +161 -5
- package/src/transformations/index.ts +43 -4
- package/src/transformations/shared-utils.ts +14 -0
- package/src/utils.ts +10 -5
|
@@ -67,9 +67,12 @@ var teleport_shared_1 = require("@teleporthq/teleport-shared");
|
|
|
67
67
|
var teleport_plugin_common_1 = require("@teleporthq/teleport-plugin-common");
|
|
68
68
|
var utils_1 = require("./utils");
|
|
69
69
|
var data_source_fetchers_1 = require("./data-source-fetchers");
|
|
70
|
+
var transformations_1 = require("./transformations");
|
|
70
71
|
var sort_utils_1 = require("./sort-utils");
|
|
71
72
|
var filter_utils_1 = require("./filter-utils");
|
|
72
73
|
var loading_state_1 = require("./loading-state");
|
|
74
|
+
var config_1 = require("./cache/config");
|
|
75
|
+
var ast_1 = require("./cache/ast");
|
|
73
76
|
// tslint:disable-next-line:no-any
|
|
74
77
|
function parseSearchDefaultValue(raw) {
|
|
75
78
|
if (!raw || typeof raw !== 'object') {
|
|
@@ -445,6 +448,7 @@ function buildStateRegistry(uidlNode) {
|
|
|
445
448
|
filterStateIds: filterStateIds,
|
|
446
449
|
filterPropIds: filterPropIds,
|
|
447
450
|
filterUrlSearchParamKeys: filterUrlSearchParamKeys,
|
|
451
|
+
cache: (0, config_1.resolveCacheFromRepeaterContent)(content.cache, parentDataSource.resourceDef),
|
|
448
452
|
category: 'plain',
|
|
449
453
|
};
|
|
450
454
|
// Determine category
|
|
@@ -578,9 +582,9 @@ function pushSearchUrlSyncEffects(effectStatements, usage, vars) {
|
|
|
578
582
|
// ==================== MAIN PLUGIN ====================
|
|
579
583
|
var createNextArrayMapperPaginationPlugin = function () {
|
|
580
584
|
var paginationPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () {
|
|
581
|
-
var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, registry, getStaticPropsChunk, isPage, stateDeclarations, effectStatements, needsUseRouter, hasRouterDecl, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, loadingStateDeclarations, dataProvidersWithoutRepeaters, searchInputs, searchEnabledUsages, paginationNodes, paginatedUsages;
|
|
582
|
-
var _a;
|
|
583
|
-
return __generator(this, function (
|
|
585
|
+
var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, registry, getStaticPropsChunk, isPage, stateDeclarations, effectStatements, needsUseRouter, hasRouterDecl, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, loadingStateDeclarations, cacheDeclarations, sharedOptions, cachedScopes, dataProvidersWithoutRepeaters, searchInputs, searchEnabledUsages, paginationNodes, paginatedUsages;
|
|
586
|
+
var _a, _b;
|
|
587
|
+
return __generator(this, function (_c) {
|
|
584
588
|
uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options;
|
|
585
589
|
componentChunk = chunks.find(function (chunk) { return chunk.name === 'jsx-component'; });
|
|
586
590
|
if (!componentChunk || componentChunk.type !== teleport_types_1.ChunkType.AST) {
|
|
@@ -942,8 +946,9 @@ var createNextArrayMapperPaginationPlugin = function () {
|
|
|
942
946
|
});
|
|
943
947
|
usageIndexByDataSourceId = new Map();
|
|
944
948
|
loadingStateDeclarations = [];
|
|
949
|
+
cacheDeclarations = [];
|
|
945
950
|
dataProvidersWithRepeaters.forEach(function (dp) {
|
|
946
|
-
var _a, _b
|
|
951
|
+
var _a, _b;
|
|
947
952
|
var nameAttr = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
|
|
948
953
|
if (!((_b = (_a = nameAttr === null || nameAttr === void 0 ? void 0 : nameAttr.value) === null || _a === void 0 ? void 0 : _a.expression) === null || _b === void 0 ? void 0 : _b.value)) {
|
|
949
954
|
return;
|
|
@@ -961,13 +966,13 @@ var createNextArrayMapperPaginationPlugin = function () {
|
|
|
961
966
|
var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
|
|
962
967
|
// Update DataProvider based on category
|
|
963
968
|
if (usage.category === 'paginated+search') {
|
|
964
|
-
updateDataProviderForPaginatedSearch(dp, usage, vars, fileName);
|
|
969
|
+
updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations);
|
|
965
970
|
}
|
|
966
971
|
else if (usage.category === 'paginated-only') {
|
|
967
|
-
updateDataProviderForPaginationOnly(dp, usage, vars, fileName);
|
|
972
|
+
updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations);
|
|
968
973
|
}
|
|
969
974
|
else if (usage.category === 'search-only') {
|
|
970
|
-
updateDataProviderForSearchOnly(dp, usage, vars, fileName);
|
|
975
|
+
updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclarations);
|
|
971
976
|
}
|
|
972
977
|
else if (usage.category === 'plain') {
|
|
973
978
|
updateDataProviderForPlain(dp, fileName, usage);
|
|
@@ -981,12 +986,37 @@ var createNextArrayMapperPaginationPlugin = function () {
|
|
|
981
986
|
loadingStateDeclarations.push.apply(loadingStateDeclarations, (0, loading_state_1.buildLoadingStateDeclarations)(loadingVars));
|
|
982
987
|
}
|
|
983
988
|
// Create API route for all categories (including 'plain' for components)
|
|
984
|
-
ensureAPIRouteExists(options.extractedResources, usage, options.dataSources, (
|
|
989
|
+
ensureAPIRouteExists(options.extractedResources, usage, options.dataSources, (0, transformations_1.buildProductTransformOptions)(options));
|
|
985
990
|
});
|
|
991
|
+
sharedOptions = options;
|
|
992
|
+
if (!sharedOptions.serverCacheByFile) {
|
|
993
|
+
sharedOptions.serverCacheByFile = new Map();
|
|
994
|
+
}
|
|
995
|
+
applyServerCacheToDataSourceModules(options.extractedResources, registry, options.dataSources, (0, transformations_1.buildProductTransformOptions)(options), sharedOptions.serverCacheByFile);
|
|
986
996
|
// Declare the loading-state hooks alongside the other data-source state, at
|
|
987
997
|
// the top of the component body. Unconditional and in a fixed order, so the
|
|
988
998
|
// hook order stays stable across renders.
|
|
989
999
|
loadingStateDeclarations.reverse().forEach(function (s) { return blockStatement.body.unshift(s); });
|
|
1000
|
+
cachedScopes = Array.from(new Set(registry.usages
|
|
1001
|
+
.filter(function (usage) { var _a; return (_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client; })
|
|
1002
|
+
.map(function (usage) { return usage.cache.scope; })));
|
|
1003
|
+
if (cacheDeclarations.length || cachedScopes.length) {
|
|
1004
|
+
// One effect per page covering every scope on it: flips the hydration
|
|
1005
|
+
// latch, then asks once whether any of this page's tables changed while
|
|
1006
|
+
// the visitor was away. Without it a browser serving everything from its
|
|
1007
|
+
// own cache would never learn about a write at all. It has to land
|
|
1008
|
+
// BEFORE the component's `return` — a plain `push` at this point in the
|
|
1009
|
+
// pipeline appends after it, where React never registers the hook.
|
|
1010
|
+
teleport_shared_1.ASTStatementOrder.insertStatementsBeforeReturn(blockStatement, [
|
|
1011
|
+
(0, ast_1.buildCacheHydrationEffect)(cachedScopes),
|
|
1012
|
+
]);
|
|
1013
|
+
// `ds_N_params` / `ds_N_cached` read the `ds_N_state` hooks declared
|
|
1014
|
+
// above, so they are placed at the earliest point where everything they
|
|
1015
|
+
// reference is already in scope — never blindly at the top, which is
|
|
1016
|
+
// exactly the `Cannot access 'ds_0_state' before initialization` crash.
|
|
1017
|
+
teleport_shared_1.ASTStatementOrder.insertStatementsAfterDependencies(blockStatement, cacheDeclarations);
|
|
1018
|
+
(0, ast_1.registerCacheClientImports)(dependencies, (_a = uidl.outputOptions) === null || _a === void 0 ? void 0 : _a.folderPath);
|
|
1019
|
+
}
|
|
990
1020
|
dataProvidersWithoutRepeaters = dataProviders.filter(function (dp) {
|
|
991
1021
|
var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
|
|
992
1022
|
return !hasRepeater;
|
|
@@ -1018,7 +1048,7 @@ var createNextArrayMapperPaginationPlugin = function () {
|
|
|
1018
1048
|
});
|
|
1019
1049
|
// STEP 6: Update getStaticProps if this is a page
|
|
1020
1050
|
if (isPage) {
|
|
1021
|
-
updateGetStaticProps(chunks, registry, dependencies, (
|
|
1051
|
+
updateGetStaticProps(chunks, registry, dependencies, (_b = uidl.outputOptions) === null || _b === void 0 ? void 0 : _b.folderPath);
|
|
1022
1052
|
}
|
|
1023
1053
|
return [2 /*return*/, structure];
|
|
1024
1054
|
});
|
|
@@ -1187,7 +1217,40 @@ function findAllPaginationNodesInJSX(blockStatement) {
|
|
|
1187
1217
|
traverse(blockStatement);
|
|
1188
1218
|
return results;
|
|
1189
1219
|
}
|
|
1190
|
-
|
|
1220
|
+
/**
|
|
1221
|
+
* Emits the provider's `params` and, for a cached mapper, the peek beside it.
|
|
1222
|
+
*
|
|
1223
|
+
* An uncached mapper keeps the inline `params={useMemo(...)}` it has always had,
|
|
1224
|
+
* byte for byte. A cached one hoists that memo into a component const so the
|
|
1225
|
+
* peek can depend on the same object identity instead of rebuilding it.
|
|
1226
|
+
*
|
|
1227
|
+
* Returns the identifier holding the peeked rows, or `undefined` when this
|
|
1228
|
+
* mapper does not cache.
|
|
1229
|
+
*/
|
|
1230
|
+
function pushParamsAttribute(
|
|
1231
|
+
// tslint:disable-next-line:no-any
|
|
1232
|
+
dp, usage, paramsProps, memoDeps, cacheDeclarations) {
|
|
1233
|
+
var _a;
|
|
1234
|
+
var paramsMemo = types.callExpression(types.identifier('useMemo'), [
|
|
1235
|
+
types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
|
|
1236
|
+
types.arrayExpression(memoDeps),
|
|
1237
|
+
]);
|
|
1238
|
+
// A state-bound sort deliberately suppresses `initialData` (see the comment at
|
|
1239
|
+
// the call site): the prefetch ran without sort params, so reusing anything on
|
|
1240
|
+
// mount would mask the current sort. The cache peek is `initialData` by
|
|
1241
|
+
// another name, so it has to be suppressed for exactly the same reason.
|
|
1242
|
+
var cache = ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) && !usage.dynamicSort ? usage.cache : undefined;
|
|
1243
|
+
if (!cache) {
|
|
1244
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(paramsMemo)));
|
|
1245
|
+
return undefined;
|
|
1246
|
+
}
|
|
1247
|
+
var hoisted = (0, ast_1.buildCachedParamsDeclarations)({ index: usage.index, paramsMemo: paramsMemo, cache: cache });
|
|
1248
|
+
cacheDeclarations.push.apply(cacheDeclarations, hoisted.declarations);
|
|
1249
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.identifier(hoisted.paramsIdentifier))));
|
|
1250
|
+
return hoisted.cachedIdentifier;
|
|
1251
|
+
}
|
|
1252
|
+
function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations) {
|
|
1253
|
+
var _a;
|
|
1191
1254
|
var attrs = dp.openingElement.attributes;
|
|
1192
1255
|
// Remove existing params, key, initialData, fetchData, persistDataDuringLoading
|
|
1193
1256
|
dp.openingElement.attributes = attrs.filter(function (attr) {
|
|
@@ -1216,10 +1279,7 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
|
|
|
1216
1279
|
(0, filter_utils_1.pushStateIdsAsDeps)(memoDeps, seenDeps, usage.dynamicSort.depStateIds);
|
|
1217
1280
|
}
|
|
1218
1281
|
pushUrlSearchParamMemoDeps(memoDeps, usage);
|
|
1219
|
-
dp
|
|
1220
|
-
types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
|
|
1221
|
-
types.arrayExpression(memoDeps),
|
|
1222
|
-
]))));
|
|
1282
|
+
var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
|
|
1223
1283
|
// Add initialData. Skip the server-prefetched data entirely when a dynamic
|
|
1224
1284
|
// state-bound sort is active — the prefetch ran without sort parameters, so
|
|
1225
1285
|
// reusing it would mask the current sort state AND cause DataProvider to skip
|
|
@@ -1228,7 +1288,7 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
|
|
|
1228
1288
|
// refetch via the useMemo params dependency chain.
|
|
1229
1289
|
if (!usage.dynamicSort) {
|
|
1230
1290
|
var initialDataCondition = wrapInitialDataWithUrlFilterGuard(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);
|
|
1231
|
-
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(initialDataCondition, types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
|
|
1291
|
+
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')))));
|
|
1232
1292
|
}
|
|
1233
1293
|
// Add key. Sort is intentionally NOT part of the key — a key change would
|
|
1234
1294
|
// remount the DataProvider, and a fresh mount re-arms the internal
|
|
@@ -1247,11 +1307,12 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
|
|
|
1247
1307
|
types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')),
|
|
1248
1308
|
]))));
|
|
1249
1309
|
// Add fetchData
|
|
1250
|
-
dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
|
|
1310
|
+
dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
|
|
1251
1311
|
// Add persistDataDuringLoading
|
|
1252
1312
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
|
|
1253
1313
|
}
|
|
1254
|
-
function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
|
|
1314
|
+
function updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations) {
|
|
1315
|
+
var _a;
|
|
1255
1316
|
var attrs = dp.openingElement.attributes;
|
|
1256
1317
|
dp.openingElement.attributes = attrs.filter(function (attr) {
|
|
1257
1318
|
var _a;
|
|
@@ -1276,14 +1337,11 @@ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
|
|
|
1276
1337
|
}
|
|
1277
1338
|
pushUrlSearchParamMemoDeps(memoDeps, usage);
|
|
1278
1339
|
// Add params
|
|
1279
|
-
dp
|
|
1280
|
-
types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
|
|
1281
|
-
types.arrayExpression(memoDeps),
|
|
1282
|
-
]))));
|
|
1340
|
+
var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
|
|
1283
1341
|
// Add initialData. See paginated+search updater for why we skip prefetch
|
|
1284
1342
|
// reuse when a dynamic state-bound sort is active.
|
|
1285
1343
|
if (!usage.dynamicSort) {
|
|
1286
|
-
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
|
|
1344
|
+
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
|
|
1287
1345
|
}
|
|
1288
1346
|
// Add key — sort is intentionally NOT included; see paginated+search updater.
|
|
1289
1347
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
|
|
@@ -1294,10 +1352,11 @@ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
|
|
|
1294
1352
|
types.templateElement({ raw: '', cooked: '' }),
|
|
1295
1353
|
], [types.identifier(vars.pageStateVar)]))));
|
|
1296
1354
|
// Add fetchData
|
|
1297
|
-
dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
|
|
1355
|
+
dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
|
|
1298
1356
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
|
|
1299
1357
|
}
|
|
1300
|
-
function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
|
|
1358
|
+
function updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclarations) {
|
|
1359
|
+
var _a;
|
|
1301
1360
|
var attrs = dp.openingElement.attributes;
|
|
1302
1361
|
dp.openingElement.attributes = attrs.filter(function (attr) {
|
|
1303
1362
|
var _a;
|
|
@@ -1323,14 +1382,11 @@ function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
|
|
|
1323
1382
|
(0, filter_utils_1.pushStateIdsAsDeps)(memoDeps, seenDeps, usage.dynamicSort.depStateIds);
|
|
1324
1383
|
}
|
|
1325
1384
|
pushUrlSearchParamMemoDeps(memoDeps, usage);
|
|
1326
|
-
dp
|
|
1327
|
-
types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
|
|
1328
|
-
types.arrayExpression(memoDeps),
|
|
1329
|
-
]))));
|
|
1385
|
+
var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
|
|
1330
1386
|
// Add initialData. See paginated+search updater for why we skip prefetch
|
|
1331
1387
|
// reuse when a dynamic state-bound sort is active.
|
|
1332
1388
|
if (!usage.dynamicSort) {
|
|
1333
|
-
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), types.identifier('undefined')))));
|
|
1389
|
+
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')))));
|
|
1334
1390
|
}
|
|
1335
1391
|
// Add key — sort is intentionally NOT included; see paginated+search updater.
|
|
1336
1392
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
|
|
@@ -1338,16 +1394,23 @@ function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
|
|
|
1338
1394
|
types.templateElement({ raw: '', cooked: '' }),
|
|
1339
1395
|
], [types.identifier(vars.debouncedSearchQueryVar)]))));
|
|
1340
1396
|
// Add fetchData
|
|
1341
|
-
dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
|
|
1397
|
+
dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
|
|
1342
1398
|
dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
|
|
1343
1399
|
}
|
|
1344
1400
|
function updateDataProviderForPlain(dp, fileName, usage) {
|
|
1345
|
-
var _a, _b, _c;
|
|
1401
|
+
var _a, _b, _c, _d;
|
|
1346
1402
|
var attrs = dp.openingElement.attributes;
|
|
1403
|
+
var clientCache = ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined;
|
|
1347
1404
|
// Check if fetchData already exists
|
|
1348
1405
|
var hasFetchData = attrs.some(function (attr) { var _a; return attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === 'fetchData'; });
|
|
1349
|
-
|
|
1350
|
-
|
|
1406
|
+
if (clientCache) {
|
|
1407
|
+
// A plain provider may already carry the UNMEMOIZED fetcher `utils.ts`
|
|
1408
|
+
// emits. Caching has to replace it rather than skip: the memoized form is
|
|
1409
|
+
// what both the cache peek and the in-flight tracking are attached to.
|
|
1410
|
+
dp.openingElement.attributes = attrs.filter(function (attr) { var _a; return !(attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === 'fetchData'); });
|
|
1411
|
+
dp.openingElement.attributes.push(createFetchDataAttribute(fileName, clientCache));
|
|
1412
|
+
}
|
|
1413
|
+
else if (!hasFetchData) {
|
|
1351
1414
|
attrs.push(createFetchDataAttribute(fileName));
|
|
1352
1415
|
}
|
|
1353
1416
|
// Check if persistDataDuringLoading already exists
|
|
@@ -1363,14 +1426,14 @@ function updateDataProviderForPlain(dp, fileName, usage) {
|
|
|
1363
1426
|
}
|
|
1364
1427
|
var paramsAttr = attrs[paramsAttrIndex];
|
|
1365
1428
|
// Check if params is already wrapped in useMemo
|
|
1366
|
-
if (((
|
|
1429
|
+
if (((_b = paramsAttr.value) === null || _b === void 0 ? void 0 : _b.type) === 'JSXExpressionContainer' &&
|
|
1367
1430
|
paramsAttr.value.expression.type === 'CallExpression' &&
|
|
1368
|
-
((
|
|
1431
|
+
((_c = paramsAttr.value.expression.callee) === null || _c === void 0 ? void 0 : _c.name) === 'useMemo') {
|
|
1369
1432
|
return;
|
|
1370
1433
|
}
|
|
1371
1434
|
// Get the current params value expression
|
|
1372
1435
|
var paramsExpression = null;
|
|
1373
|
-
if (((
|
|
1436
|
+
if (((_d = paramsAttr.value) === null || _d === void 0 ? void 0 : _d.type) === 'JSXExpressionContainer') {
|
|
1374
1437
|
paramsExpression = paramsAttr.value.expression;
|
|
1375
1438
|
}
|
|
1376
1439
|
if (!paramsExpression) {
|
|
@@ -1422,32 +1485,32 @@ function stabilizeDataProviderWithoutRepeater(dp) {
|
|
|
1422
1485
|
// Replace the params attribute
|
|
1423
1486
|
attrs[paramsAttrIndex] = types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(memoizedParams));
|
|
1424
1487
|
}
|
|
1425
|
-
function createFetchDataAttribute(fileName) {
|
|
1426
|
-
|
|
1427
|
-
types.
|
|
1428
|
-
types.
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
]))
|
|
1449
|
-
types.
|
|
1450
|
-
])));
|
|
1488
|
+
function createFetchDataAttribute(fileName, cache) {
|
|
1489
|
+
var fetchCall = types.callExpression(types.identifier('fetch'), [
|
|
1490
|
+
types.templateLiteral([
|
|
1491
|
+
types.templateElement({
|
|
1492
|
+
raw: "/api/".concat(fileName, "?"),
|
|
1493
|
+
cooked: "/api/".concat(fileName, "?"),
|
|
1494
|
+
}),
|
|
1495
|
+
types.templateElement({ raw: '', cooked: '' }),
|
|
1496
|
+
], [types.newExpression(types.identifier('URLSearchParams'), [types.identifier('params')])]),
|
|
1497
|
+
types.objectExpression([
|
|
1498
|
+
types.objectProperty(types.identifier('headers'), types.objectExpression([
|
|
1499
|
+
types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
|
|
1500
|
+
])),
|
|
1501
|
+
]),
|
|
1502
|
+
]);
|
|
1503
|
+
var parsedJson = types.callExpression(types.memberExpression(fetchCall, types.identifier('then')), [
|
|
1504
|
+
types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
|
|
1505
|
+
]);
|
|
1506
|
+
// The uncached tail is left exactly as it has always been emitted, so a
|
|
1507
|
+
// project that does not cache produces byte-identical output.
|
|
1508
|
+
var uncachedTail = types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true));
|
|
1509
|
+
var networkChain = types.callExpression(types.memberExpression(parsedJson, types.identifier('then')), [cache ? (0, ast_1.buildCacheStoreThen)(cache) : uncachedTail]);
|
|
1510
|
+
var arrow = cache
|
|
1511
|
+
? types.arrowFunctionExpression([types.identifier('params')], (0, ast_1.buildCachedFetchBody)(networkChain, cache))
|
|
1512
|
+
: types.arrowFunctionExpression([types.identifier('params')], networkChain);
|
|
1513
|
+
return types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(types.callExpression(types.identifier('useCallback'), [arrow, types.arrayExpression([])])));
|
|
1451
1514
|
}
|
|
1452
1515
|
function wireSearchInput(inputNode, vars) {
|
|
1453
1516
|
// Remove existing onChange and value
|
|
@@ -1554,7 +1617,84 @@ function wirePaginationButtons(paginationNode, usage, vars) {
|
|
|
1554
1617
|
}
|
|
1555
1618
|
}
|
|
1556
1619
|
}
|
|
1557
|
-
|
|
1620
|
+
/**
|
|
1621
|
+
* Applies the SERVER cache to the generated data-source modules, once, after
|
|
1622
|
+
* every provider has been visited.
|
|
1623
|
+
*
|
|
1624
|
+
* A post-pass rather than a parameter to `ensureAPIRouteExists` because four
|
|
1625
|
+
* different places race to create `utils/data-sources/<file>.js` — the
|
|
1626
|
+
* getStaticProps path, the component path, the client-API path and this plugin —
|
|
1627
|
+
* and whichever wins would otherwise decide whether the file is cached. Since
|
|
1628
|
+
* the generator is deterministic, regenerating the winner with the cache options
|
|
1629
|
+
* is order-independent and cannot half-apply.
|
|
1630
|
+
*
|
|
1631
|
+
* The config is merged per FILE, not per mapper: one module serves every mapper
|
|
1632
|
+
* reading that `(type, table, dataSourceId)` triple, so two mappers on two pages
|
|
1633
|
+
* have to agree — and the fresher one wins (see `mergeServerCacheOptions`).
|
|
1634
|
+
*/
|
|
1635
|
+
function applyServerCacheToDataSourceModules(
|
|
1636
|
+
// tslint:disable-next-line:no-any
|
|
1637
|
+
extractedResources, registry,
|
|
1638
|
+
// tslint:disable-next-line:no-any
|
|
1639
|
+
dataSources, transformOptions,
|
|
1640
|
+
// Accumulated across every page/component this generation has processed. The
|
|
1641
|
+
// module is shared project-wide, so merging only the CURRENT page's usages
|
|
1642
|
+
// would let page ORDER decide the TTL: a page asking for 300s processed after
|
|
1643
|
+
// one asking for 60s would widen the window the second page was configured
|
|
1644
|
+
// with. Carried on the shared options object so the merge stays global.
|
|
1645
|
+
accumulator) {
|
|
1646
|
+
if (transformOptions === void 0) { transformOptions = {}; }
|
|
1647
|
+
var byFileName = accumulator !== null && accumulator !== void 0 ? accumulator : new Map();
|
|
1648
|
+
registry.usages.forEach(function (usage) {
|
|
1649
|
+
var _a;
|
|
1650
|
+
if (!((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.server)) {
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
|
|
1654
|
+
var bucket = byFileName.get(fileName) || { usage: usage, entries: [] };
|
|
1655
|
+
bucket.entries.push({
|
|
1656
|
+
scope: usage.cache.scope,
|
|
1657
|
+
ttlSeconds: usage.cache.ttlSeconds,
|
|
1658
|
+
sMaxAge: usage.cache.sMaxAge,
|
|
1659
|
+
staleWhileRevalidate: usage.cache.staleWhileRevalidate,
|
|
1660
|
+
});
|
|
1661
|
+
byFileName.set(fileName, bucket);
|
|
1662
|
+
});
|
|
1663
|
+
byFileName.forEach(function (bucket, fileName) {
|
|
1664
|
+
var cacheOptions = (0, config_1.mergeServerCacheOptions)(bucket.entries);
|
|
1665
|
+
if (!cacheOptions) {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
var dataSource = dataSources[bucket.usage.resourceDefinition.dataSourceId];
|
|
1669
|
+
if (!dataSource) {
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
var tableName = bucket.usage.resourceDefinition.tableName || 'data';
|
|
1673
|
+
var utilsKey = "utils/".concat(fileName);
|
|
1674
|
+
var apiKey = "api/".concat(fileName);
|
|
1675
|
+
try {
|
|
1676
|
+
if (extractedResources[utilsKey]) {
|
|
1677
|
+
extractedResources[utilsKey].content = (0, data_source_fetchers_1.generateDataSourceFetcherWithCore)(dataSource, tableName, false, transformOptions, cacheOptions);
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1680
|
+
// The variant that inlines the whole fetcher straight into `pages/api`
|
|
1681
|
+
// instead of re-exporting a utils module. Detected by content rather than
|
|
1682
|
+
// by which code path produced it, so a future fifth emitter is covered too.
|
|
1683
|
+
var apiEntry = extractedResources[apiKey];
|
|
1684
|
+
if (apiEntry &&
|
|
1685
|
+
typeof apiEntry.content === 'string' &&
|
|
1686
|
+
apiEntry.content.includes('async function handler')) {
|
|
1687
|
+
apiEntry.content = (0, data_source_fetchers_1.generateDataSourceFetcherWithCore)(dataSource, tableName, true, transformOptions, cacheOptions);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
catch (error) {
|
|
1691
|
+
// Caching must never be the reason a project fails to generate; the
|
|
1692
|
+
// uncached module that is already in place stays exactly as it was.
|
|
1693
|
+
}
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
function ensureAPIRouteExists(extractedResources, usage, dataSources, transformOptions) {
|
|
1697
|
+
if (transformOptions === void 0) { transformOptions = {}; }
|
|
1558
1698
|
// Generate file name for the API route
|
|
1559
1699
|
var fileName = (0, utils_1.generateSafeFileName)(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
|
|
1560
1700
|
// Check if the utils data source file exists - if not, create it
|
|
@@ -1564,7 +1704,7 @@ function ensureAPIRouteExists(extractedResources, usage, dataSources, categories
|
|
|
1564
1704
|
if (dataSource) {
|
|
1565
1705
|
try {
|
|
1566
1706
|
// Generate the utils file with fetchData, fetchCount, handler, and getCount
|
|
1567
|
-
var fetcherCode = (0, data_source_fetchers_1.generateDataSourceFetcherWithCore)(dataSource, usage.resourceDefinition.tableName || 'data', false,
|
|
1707
|
+
var fetcherCode = (0, data_source_fetchers_1.generateDataSourceFetcherWithCore)(dataSource, usage.resourceDefinition.tableName || 'data', false, transformOptions);
|
|
1568
1708
|
extractedResources["utils/".concat(fileName)] = {
|
|
1569
1709
|
fileName: fileName,
|
|
1570
1710
|
fileType: teleport_types_1.FileType.JS,
|