@wdprlib/parser 5.2.0 → 5.3.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/dist/index.cjs +110 -18
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +110 -18
- package/package.json +2 -2
- package/src/build-info.generated.ts +2 -2
- package/src/parser/rules/block/module/listpages/resolution/items.ts +2 -2
- package/src/parser/rules/block/module/listpages/resolution/pager.ts +43 -0
- package/src/parser/rules/block/module/listpages/resolution/wrapper.ts +6 -1
- package/src/parser/rules/block/module/listpages/resolve.ts +1 -1
- package/src/parser/rules/block/module/listpages/types/external-data.ts +13 -0
- package/src/parser/rules/block/module/listpages/url-resolution/params.ts +5 -4
- package/src/parser/rules/block/module/resolution/data-maps.ts +75 -3
- package/src/parser/rules/block/module/resolution/resolve-async.ts +12 -3
- package/src/pipeline/process.ts +8 -1
package/dist/index.cjs
CHANGED
|
@@ -82,8 +82,8 @@ module.exports = __toCommonJS(exports_src);
|
|
|
82
82
|
|
|
83
83
|
// packages/parser/src/build-info.generated.ts
|
|
84
84
|
var buildInfo = Object.freeze({
|
|
85
|
-
version: "5.
|
|
86
|
-
sha: "
|
|
85
|
+
version: "5.3.0",
|
|
86
|
+
sha: "b71b84c705e05717f5ea12fd89684a91b669dbff",
|
|
87
87
|
dirty: false
|
|
88
88
|
});
|
|
89
89
|
|
|
@@ -6253,9 +6253,9 @@ function renderListPagesItems(module2, data, compiledTemplate, parse) {
|
|
|
6253
6253
|
continue;
|
|
6254
6254
|
const ctx = {
|
|
6255
6255
|
page,
|
|
6256
|
-
index: i + 1,
|
|
6256
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
6257
6257
|
total: data.totalCount,
|
|
6258
|
-
limit: module2.limit,
|
|
6258
|
+
limit: data.pagination ? data.pagination.limit : module2.limit,
|
|
6259
6259
|
site: data.site
|
|
6260
6260
|
};
|
|
6261
6261
|
const itemAst = getModuleParseAst(parse(compiledTemplate(ctx)));
|
|
@@ -6275,9 +6275,46 @@ function renderListPagesItems(module2, data, compiledTemplate, parse) {
|
|
|
6275
6275
|
return items;
|
|
6276
6276
|
}
|
|
6277
6277
|
|
|
6278
|
+
// packages/parser/src/parser/rules/block/module/listpages/resolution/pager.ts
|
|
6279
|
+
function createListPagesPager(data) {
|
|
6280
|
+
const pagination = data.pagination;
|
|
6281
|
+
if (!pagination || pagination.totalPages <= 1)
|
|
6282
|
+
return [];
|
|
6283
|
+
const { currentPage, totalPages, urlPath, parameter } = pagination;
|
|
6284
|
+
const pages = new Set([1, totalPages]);
|
|
6285
|
+
for (let page = Math.max(1, currentPage - 2);page <= Math.min(totalPages, currentPage + 2); page++) {
|
|
6286
|
+
pages.add(page);
|
|
6287
|
+
}
|
|
6288
|
+
return [
|
|
6289
|
+
{
|
|
6290
|
+
element: "pager",
|
|
6291
|
+
data: {
|
|
6292
|
+
currentPage,
|
|
6293
|
+
totalPages,
|
|
6294
|
+
pages: [...pages].sort((a, b) => a - b).map((page) => ({
|
|
6295
|
+
page,
|
|
6296
|
+
href: pageUrl(urlPath, parameter, page)
|
|
6297
|
+
}))
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
];
|
|
6301
|
+
}
|
|
6302
|
+
function pageUrl(urlPath, parameter, page) {
|
|
6303
|
+
const suffixStart = urlPath.search(/[?#]/);
|
|
6304
|
+
const path = suffixStart === -1 ? urlPath : urlPath.slice(0, suffixStart);
|
|
6305
|
+
const suffix = suffixStart === -1 ? "" : urlPath.slice(suffixStart);
|
|
6306
|
+
const parts = path.split("/");
|
|
6307
|
+
const result = parts.slice(0, 2);
|
|
6308
|
+
for (let index = 2;index < parts.length; index += 2) {
|
|
6309
|
+
if (parts[index] !== parameter)
|
|
6310
|
+
result.push(...parts.slice(index, index + 2));
|
|
6311
|
+
}
|
|
6312
|
+
return `${result.join("/").replace(/\/$/, "")}/${parameter}/${page}${suffix}`;
|
|
6313
|
+
}
|
|
6314
|
+
|
|
6278
6315
|
// packages/parser/src/parser/rules/block/module/listpages/resolution/wrapper.ts
|
|
6279
|
-
function wrapListPagesResult(module2, items, parse) {
|
|
6280
|
-
if (items.length === 0) {
|
|
6316
|
+
function wrapListPagesResult(module2, items, parse, data) {
|
|
6317
|
+
if (items.length === 0 && (!data || data.pages.length === 0)) {
|
|
6281
6318
|
return [];
|
|
6282
6319
|
}
|
|
6283
6320
|
const result = [];
|
|
@@ -6290,6 +6327,8 @@ function wrapListPagesResult(module2, items, parse) {
|
|
|
6290
6327
|
const appendAst = getModuleParseAst(parse(module2["append-line"]));
|
|
6291
6328
|
result.push(...appendAst.elements);
|
|
6292
6329
|
}
|
|
6330
|
+
if (data)
|
|
6331
|
+
result.push(...createListPagesPager(data));
|
|
6293
6332
|
if (module2.wrapper) {
|
|
6294
6333
|
return [
|
|
6295
6334
|
{
|
|
@@ -6311,7 +6350,7 @@ function isListPagesModule2(module2) {
|
|
|
6311
6350
|
}
|
|
6312
6351
|
function resolveListPages(module2, data, compiledTemplate, parse) {
|
|
6313
6352
|
const items = renderListPagesItems(module2, data, compiledTemplate, parse);
|
|
6314
|
-
return wrapListPagesResult(module2, items, parse);
|
|
6353
|
+
return wrapListPagesResult(module2, items, parse, data);
|
|
6315
6354
|
}
|
|
6316
6355
|
// packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
|
|
6317
6356
|
function definePageData(input) {
|
|
@@ -6408,10 +6447,10 @@ var URL_RESOLVABLE_FIELDS = [
|
|
|
6408
6447
|
];
|
|
6409
6448
|
|
|
6410
6449
|
// packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
|
|
6411
|
-
function parseUrlParams(url) {
|
|
6450
|
+
function parseUrlParams(url, hasPageName = false) {
|
|
6412
6451
|
const params = new Map;
|
|
6413
|
-
const parts = url.split("/").filter(Boolean);
|
|
6414
|
-
const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
|
|
6452
|
+
const parts = url.split(/[?#]/, 1)[0].split("/").filter(Boolean);
|
|
6453
|
+
const pairStart = !hasPageName && isUrlParameter(parts[0]) ? 0 : 1;
|
|
6415
6454
|
for (let i = pairStart;i < parts.length - 1; i += 2) {
|
|
6416
6455
|
const key = parts[i];
|
|
6417
6456
|
const value = parts[i + 1];
|
|
@@ -7509,18 +7548,66 @@ function resolveListUsers(_module, data, compiledTemplate, parse) {
|
|
|
7509
7548
|
return itemAst.elements;
|
|
7510
7549
|
}
|
|
7511
7550
|
// packages/parser/src/parser/rules/block/module/resolution/data-maps.ts
|
|
7512
|
-
async function buildListPagesDataMap(dataProvider, requirements, urlPath) {
|
|
7551
|
+
async function buildListPagesDataMap(dataProvider, requirements, urlPath, paginationState = { nextUnprefixed: 1 }) {
|
|
7513
7552
|
const dataMap = new Map;
|
|
7514
|
-
const urlParams = parseUrlParams(urlPath ?? "");
|
|
7553
|
+
const urlParams = parseUrlParams(urlPath ?? "", true);
|
|
7515
7554
|
for (const req of requirements) {
|
|
7516
7555
|
const normalizedQuery = resolveAndNormalizeQuery(req, urlParams);
|
|
7517
|
-
|
|
7556
|
+
if (!urlPath || !urlPath.startsWith("/") || urlPath.startsWith("//")) {
|
|
7557
|
+
const data2 = await dataProvider.fetchListPages?.(normalizedQuery, req);
|
|
7558
|
+
if (data2)
|
|
7559
|
+
dataMap.set(req.id, data2);
|
|
7560
|
+
continue;
|
|
7561
|
+
}
|
|
7562
|
+
const ordinal = req.urlAttrPrefix ? 0 : paginationState.nextUnprefixed++;
|
|
7563
|
+
const parameter = req.urlAttrPrefix ? `${encodeURIComponent(req.urlAttrPrefix)}_p` : ordinal === 1 ? "p" : `p${ordinal}`;
|
|
7564
|
+
const perPage = Math.min(250, positiveInteger(normalizedQuery.perPage, 20));
|
|
7565
|
+
const baseOffset = positiveInteger(normalizedQuery.offset, 0);
|
|
7566
|
+
const limit = normalizedQuery.limit !== undefined && normalizedQuery.limit >= 0 ? Math.floor(normalizedQuery.limit) : undefined;
|
|
7567
|
+
const rawPage = urlParams.get(parameter) ?? "1";
|
|
7568
|
+
let currentPage = /^\d+$/.test(rawPage) ? positiveInteger(Number(rawPage), 1) : 1;
|
|
7569
|
+
currentPage = Math.min(currentPage, Math.floor((Number.MAX_SAFE_INTEGER - baseOffset) / perPage) + 1);
|
|
7570
|
+
if (limit !== undefined)
|
|
7571
|
+
currentPage = Math.min(currentPage, Math.max(1, Math.ceil(limit / perPage)));
|
|
7572
|
+
const fetchPage = () => {
|
|
7573
|
+
const relativeOffset = (currentPage - 1) * perPage;
|
|
7574
|
+
return dataProvider.fetchListPages?.({
|
|
7575
|
+
...normalizedQuery,
|
|
7576
|
+
offset: baseOffset + relativeOffset,
|
|
7577
|
+
limit: Math.min(perPage, limit === undefined ? perPage : Math.max(0, limit - relativeOffset)),
|
|
7578
|
+
perPage
|
|
7579
|
+
}, req);
|
|
7580
|
+
};
|
|
7581
|
+
let data = await fetchPage();
|
|
7518
7582
|
if (data) {
|
|
7519
|
-
|
|
7583
|
+
const count = Math.min(Math.max(0, data.totalCount - baseOffset), limit ?? Infinity);
|
|
7584
|
+
const totalPages = Math.ceil(count / perPage);
|
|
7585
|
+
const lastPage = Math.max(1, totalPages);
|
|
7586
|
+
if (currentPage > lastPage) {
|
|
7587
|
+
currentPage = lastPage;
|
|
7588
|
+
data = await fetchPage();
|
|
7589
|
+
}
|
|
7590
|
+
if (data)
|
|
7591
|
+
dataMap.set(req.id, {
|
|
7592
|
+
...data,
|
|
7593
|
+
pages: data.pages.slice(0, Math.min(perPage, Math.max(0, count - (currentPage - 1) * perPage))),
|
|
7594
|
+
pagination: {
|
|
7595
|
+
currentPage,
|
|
7596
|
+
perPage,
|
|
7597
|
+
totalPages,
|
|
7598
|
+
offset: baseOffset + (currentPage - 1) * perPage,
|
|
7599
|
+
limit,
|
|
7600
|
+
urlPath,
|
|
7601
|
+
parameter
|
|
7602
|
+
}
|
|
7603
|
+
});
|
|
7520
7604
|
}
|
|
7521
7605
|
}
|
|
7522
7606
|
return dataMap;
|
|
7523
7607
|
}
|
|
7608
|
+
function positiveInteger(value, fallback) {
|
|
7609
|
+
return value !== undefined && Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
7610
|
+
}
|
|
7524
7611
|
async function buildListUsersDataMap(dataProvider, requirements) {
|
|
7525
7612
|
const dataMap = new Map;
|
|
7526
7613
|
for (const req of requirements) {
|
|
@@ -14388,7 +14475,7 @@ async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
|
|
|
14388
14475
|
registry.register(ast);
|
|
14389
14476
|
const parse2 = async (source) => registry.register(await options.parse(source));
|
|
14390
14477
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
14391
|
-
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath),
|
|
14478
|
+
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath, options.paginationState),
|
|
14392
14479
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
14393
14480
|
buildTagCloudDataMap(dataProvider, options.requirements.tagCloud ?? [])
|
|
14394
14481
|
]);
|
|
@@ -14476,9 +14563,9 @@ async function resolveListPagesAsync(module2, data, template, parse2) {
|
|
|
14476
14563
|
continue;
|
|
14477
14564
|
const variableContext = {
|
|
14478
14565
|
page,
|
|
14479
|
-
index: i + 1,
|
|
14566
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
14480
14567
|
total: data.totalCount,
|
|
14481
|
-
limit: module2.limit,
|
|
14568
|
+
limit: data.pagination ? data.pagination.limit : module2.limit,
|
|
14482
14569
|
site: data.site
|
|
14483
14570
|
};
|
|
14484
14571
|
const parsed = await parse2(template(variableContext));
|
|
@@ -14498,6 +14585,7 @@ async function resolveListPagesAsync(module2, data, template, parse2) {
|
|
|
14498
14585
|
if (module2["append-line"] && !module2.separate) {
|
|
14499
14586
|
result.push(...(await parse2(module2["append-line"])).elements);
|
|
14500
14587
|
}
|
|
14588
|
+
result.push(...createListPagesPager(data));
|
|
14501
14589
|
return module2.wrapper ? [
|
|
14502
14590
|
{
|
|
14503
14591
|
element: "container",
|
|
@@ -14598,6 +14686,9 @@ async function processWikitext(source, options) {
|
|
|
14598
14686
|
const dataProvider = createModuleDataProvider(options, callbackContext);
|
|
14599
14687
|
const parseFragment = parseSource2;
|
|
14600
14688
|
let ast = initial.ast;
|
|
14689
|
+
const paginationState = { nextUnprefixed: 1 };
|
|
14690
|
+
const requestedPath = options.page.urlPath;
|
|
14691
|
+
const urlPath = !requestedPath || /^\/(?:[?#]|$)/.test(requestedPath) ? `/${options.page.fullName}${requestedPath?.slice(1) ?? ""}` : requestedPath;
|
|
14601
14692
|
for (let pass = 0;pass < DEFAULT_MODULE_MAX_PASSES; pass++) {
|
|
14602
14693
|
const extraction = extractDataRequirements(ast);
|
|
14603
14694
|
if (pass > 0 && !hasResolvableRequirements(extraction.requirements, options.dataProvider)) {
|
|
@@ -14608,7 +14699,8 @@ async function processWikitext(source, options) {
|
|
|
14608
14699
|
compiledListPagesTemplates: extraction.compiledListPagesTemplates,
|
|
14609
14700
|
compiledListUsersTemplates: extraction.compiledListUsersTemplates,
|
|
14610
14701
|
requirements: extraction.requirements,
|
|
14611
|
-
urlPath
|
|
14702
|
+
urlPath,
|
|
14703
|
+
paginationState,
|
|
14612
14704
|
pageTags: options.page.tags
|
|
14613
14705
|
});
|
|
14614
14706
|
ast = resolved.ast;
|
package/dist/index.d.cts
CHANGED
|
@@ -691,8 +691,21 @@ interface SiteContext {
|
|
|
691
691
|
*/
|
|
692
692
|
interface ListPagesExternalData {
|
|
693
693
|
pages: PageData[];
|
|
694
|
+
/** Matching items before offset and limit; use the same visibility filters as pages. */
|
|
694
695
|
totalCount: number;
|
|
695
696
|
site: SiteContext;
|
|
697
|
+
/** Filled by module resolution when a page URL is available. */
|
|
698
|
+
pagination?: {
|
|
699
|
+
currentPage: number;
|
|
700
|
+
perPage: number;
|
|
701
|
+
totalPages: number;
|
|
702
|
+
/** Actual fetch offset, including the module's starting offset. */
|
|
703
|
+
offset: number;
|
|
704
|
+
/** Total item limit after URL resolution, not the fetch batch size. */
|
|
705
|
+
limit?: number;
|
|
706
|
+
urlPath: string;
|
|
707
|
+
parameter: string;
|
|
708
|
+
};
|
|
696
709
|
}
|
|
697
710
|
/**
|
|
698
711
|
* Normalized tags selector.
|
package/dist/index.d.ts
CHANGED
|
@@ -691,8 +691,21 @@ interface SiteContext {
|
|
|
691
691
|
*/
|
|
692
692
|
interface ListPagesExternalData {
|
|
693
693
|
pages: PageData[];
|
|
694
|
+
/** Matching items before offset and limit; use the same visibility filters as pages. */
|
|
694
695
|
totalCount: number;
|
|
695
696
|
site: SiteContext;
|
|
697
|
+
/** Filled by module resolution when a page URL is available. */
|
|
698
|
+
pagination?: {
|
|
699
|
+
currentPage: number;
|
|
700
|
+
perPage: number;
|
|
701
|
+
totalPages: number;
|
|
702
|
+
/** Actual fetch offset, including the module's starting offset. */
|
|
703
|
+
offset: number;
|
|
704
|
+
/** Total item limit after URL resolution, not the fetch batch size. */
|
|
705
|
+
limit?: number;
|
|
706
|
+
urlPath: string;
|
|
707
|
+
parameter: string;
|
|
708
|
+
};
|
|
696
709
|
}
|
|
697
710
|
/**
|
|
698
711
|
* Normalized tags selector.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/parser/src/build-info.generated.ts
|
|
2
2
|
var buildInfo = Object.freeze({
|
|
3
|
-
version: "5.
|
|
4
|
-
sha: "
|
|
3
|
+
version: "5.3.0",
|
|
4
|
+
sha: "b71b84c705e05717f5ea12fd89684a91b669dbff",
|
|
5
5
|
dirty: false
|
|
6
6
|
});
|
|
7
7
|
|
|
@@ -6186,9 +6186,9 @@ function renderListPagesItems(module, data, compiledTemplate, parse) {
|
|
|
6186
6186
|
continue;
|
|
6187
6187
|
const ctx = {
|
|
6188
6188
|
page,
|
|
6189
|
-
index: i + 1,
|
|
6189
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
6190
6190
|
total: data.totalCount,
|
|
6191
|
-
limit: module.limit,
|
|
6191
|
+
limit: data.pagination ? data.pagination.limit : module.limit,
|
|
6192
6192
|
site: data.site
|
|
6193
6193
|
};
|
|
6194
6194
|
const itemAst = getModuleParseAst(parse(compiledTemplate(ctx)));
|
|
@@ -6208,9 +6208,46 @@ function renderListPagesItems(module, data, compiledTemplate, parse) {
|
|
|
6208
6208
|
return items;
|
|
6209
6209
|
}
|
|
6210
6210
|
|
|
6211
|
+
// packages/parser/src/parser/rules/block/module/listpages/resolution/pager.ts
|
|
6212
|
+
function createListPagesPager(data) {
|
|
6213
|
+
const pagination = data.pagination;
|
|
6214
|
+
if (!pagination || pagination.totalPages <= 1)
|
|
6215
|
+
return [];
|
|
6216
|
+
const { currentPage, totalPages, urlPath, parameter } = pagination;
|
|
6217
|
+
const pages = new Set([1, totalPages]);
|
|
6218
|
+
for (let page = Math.max(1, currentPage - 2);page <= Math.min(totalPages, currentPage + 2); page++) {
|
|
6219
|
+
pages.add(page);
|
|
6220
|
+
}
|
|
6221
|
+
return [
|
|
6222
|
+
{
|
|
6223
|
+
element: "pager",
|
|
6224
|
+
data: {
|
|
6225
|
+
currentPage,
|
|
6226
|
+
totalPages,
|
|
6227
|
+
pages: [...pages].sort((a, b) => a - b).map((page) => ({
|
|
6228
|
+
page,
|
|
6229
|
+
href: pageUrl(urlPath, parameter, page)
|
|
6230
|
+
}))
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
6233
|
+
];
|
|
6234
|
+
}
|
|
6235
|
+
function pageUrl(urlPath, parameter, page) {
|
|
6236
|
+
const suffixStart = urlPath.search(/[?#]/);
|
|
6237
|
+
const path = suffixStart === -1 ? urlPath : urlPath.slice(0, suffixStart);
|
|
6238
|
+
const suffix = suffixStart === -1 ? "" : urlPath.slice(suffixStart);
|
|
6239
|
+
const parts = path.split("/");
|
|
6240
|
+
const result = parts.slice(0, 2);
|
|
6241
|
+
for (let index = 2;index < parts.length; index += 2) {
|
|
6242
|
+
if (parts[index] !== parameter)
|
|
6243
|
+
result.push(...parts.slice(index, index + 2));
|
|
6244
|
+
}
|
|
6245
|
+
return `${result.join("/").replace(/\/$/, "")}/${parameter}/${page}${suffix}`;
|
|
6246
|
+
}
|
|
6247
|
+
|
|
6211
6248
|
// packages/parser/src/parser/rules/block/module/listpages/resolution/wrapper.ts
|
|
6212
|
-
function wrapListPagesResult(module, items, parse) {
|
|
6213
|
-
if (items.length === 0) {
|
|
6249
|
+
function wrapListPagesResult(module, items, parse, data) {
|
|
6250
|
+
if (items.length === 0 && (!data || data.pages.length === 0)) {
|
|
6214
6251
|
return [];
|
|
6215
6252
|
}
|
|
6216
6253
|
const result = [];
|
|
@@ -6223,6 +6260,8 @@ function wrapListPagesResult(module, items, parse) {
|
|
|
6223
6260
|
const appendAst = getModuleParseAst(parse(module["append-line"]));
|
|
6224
6261
|
result.push(...appendAst.elements);
|
|
6225
6262
|
}
|
|
6263
|
+
if (data)
|
|
6264
|
+
result.push(...createListPagesPager(data));
|
|
6226
6265
|
if (module.wrapper) {
|
|
6227
6266
|
return [
|
|
6228
6267
|
{
|
|
@@ -6244,7 +6283,7 @@ function isListPagesModule2(module) {
|
|
|
6244
6283
|
}
|
|
6245
6284
|
function resolveListPages(module, data, compiledTemplate, parse) {
|
|
6246
6285
|
const items = renderListPagesItems(module, data, compiledTemplate, parse);
|
|
6247
|
-
return wrapListPagesResult(module, items, parse);
|
|
6286
|
+
return wrapListPagesResult(module, items, parse, data);
|
|
6248
6287
|
}
|
|
6249
6288
|
// packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
|
|
6250
6289
|
function definePageData(input) {
|
|
@@ -6341,10 +6380,10 @@ var URL_RESOLVABLE_FIELDS = [
|
|
|
6341
6380
|
];
|
|
6342
6381
|
|
|
6343
6382
|
// packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
|
|
6344
|
-
function parseUrlParams(url) {
|
|
6383
|
+
function parseUrlParams(url, hasPageName = false) {
|
|
6345
6384
|
const params = new Map;
|
|
6346
|
-
const parts = url.split("/").filter(Boolean);
|
|
6347
|
-
const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
|
|
6385
|
+
const parts = url.split(/[?#]/, 1)[0].split("/").filter(Boolean);
|
|
6386
|
+
const pairStart = !hasPageName && isUrlParameter(parts[0]) ? 0 : 1;
|
|
6348
6387
|
for (let i = pairStart;i < parts.length - 1; i += 2) {
|
|
6349
6388
|
const key = parts[i];
|
|
6350
6389
|
const value = parts[i + 1];
|
|
@@ -7442,18 +7481,66 @@ function resolveListUsers(_module, data, compiledTemplate, parse) {
|
|
|
7442
7481
|
return itemAst.elements;
|
|
7443
7482
|
}
|
|
7444
7483
|
// packages/parser/src/parser/rules/block/module/resolution/data-maps.ts
|
|
7445
|
-
async function buildListPagesDataMap(dataProvider, requirements, urlPath) {
|
|
7484
|
+
async function buildListPagesDataMap(dataProvider, requirements, urlPath, paginationState = { nextUnprefixed: 1 }) {
|
|
7446
7485
|
const dataMap = new Map;
|
|
7447
|
-
const urlParams = parseUrlParams(urlPath ?? "");
|
|
7486
|
+
const urlParams = parseUrlParams(urlPath ?? "", true);
|
|
7448
7487
|
for (const req of requirements) {
|
|
7449
7488
|
const normalizedQuery = resolveAndNormalizeQuery(req, urlParams);
|
|
7450
|
-
|
|
7489
|
+
if (!urlPath || !urlPath.startsWith("/") || urlPath.startsWith("//")) {
|
|
7490
|
+
const data2 = await dataProvider.fetchListPages?.(normalizedQuery, req);
|
|
7491
|
+
if (data2)
|
|
7492
|
+
dataMap.set(req.id, data2);
|
|
7493
|
+
continue;
|
|
7494
|
+
}
|
|
7495
|
+
const ordinal = req.urlAttrPrefix ? 0 : paginationState.nextUnprefixed++;
|
|
7496
|
+
const parameter = req.urlAttrPrefix ? `${encodeURIComponent(req.urlAttrPrefix)}_p` : ordinal === 1 ? "p" : `p${ordinal}`;
|
|
7497
|
+
const perPage = Math.min(250, positiveInteger(normalizedQuery.perPage, 20));
|
|
7498
|
+
const baseOffset = positiveInteger(normalizedQuery.offset, 0);
|
|
7499
|
+
const limit = normalizedQuery.limit !== undefined && normalizedQuery.limit >= 0 ? Math.floor(normalizedQuery.limit) : undefined;
|
|
7500
|
+
const rawPage = urlParams.get(parameter) ?? "1";
|
|
7501
|
+
let currentPage = /^\d+$/.test(rawPage) ? positiveInteger(Number(rawPage), 1) : 1;
|
|
7502
|
+
currentPage = Math.min(currentPage, Math.floor((Number.MAX_SAFE_INTEGER - baseOffset) / perPage) + 1);
|
|
7503
|
+
if (limit !== undefined)
|
|
7504
|
+
currentPage = Math.min(currentPage, Math.max(1, Math.ceil(limit / perPage)));
|
|
7505
|
+
const fetchPage = () => {
|
|
7506
|
+
const relativeOffset = (currentPage - 1) * perPage;
|
|
7507
|
+
return dataProvider.fetchListPages?.({
|
|
7508
|
+
...normalizedQuery,
|
|
7509
|
+
offset: baseOffset + relativeOffset,
|
|
7510
|
+
limit: Math.min(perPage, limit === undefined ? perPage : Math.max(0, limit - relativeOffset)),
|
|
7511
|
+
perPage
|
|
7512
|
+
}, req);
|
|
7513
|
+
};
|
|
7514
|
+
let data = await fetchPage();
|
|
7451
7515
|
if (data) {
|
|
7452
|
-
|
|
7516
|
+
const count = Math.min(Math.max(0, data.totalCount - baseOffset), limit ?? Infinity);
|
|
7517
|
+
const totalPages = Math.ceil(count / perPage);
|
|
7518
|
+
const lastPage = Math.max(1, totalPages);
|
|
7519
|
+
if (currentPage > lastPage) {
|
|
7520
|
+
currentPage = lastPage;
|
|
7521
|
+
data = await fetchPage();
|
|
7522
|
+
}
|
|
7523
|
+
if (data)
|
|
7524
|
+
dataMap.set(req.id, {
|
|
7525
|
+
...data,
|
|
7526
|
+
pages: data.pages.slice(0, Math.min(perPage, Math.max(0, count - (currentPage - 1) * perPage))),
|
|
7527
|
+
pagination: {
|
|
7528
|
+
currentPage,
|
|
7529
|
+
perPage,
|
|
7530
|
+
totalPages,
|
|
7531
|
+
offset: baseOffset + (currentPage - 1) * perPage,
|
|
7532
|
+
limit,
|
|
7533
|
+
urlPath,
|
|
7534
|
+
parameter
|
|
7535
|
+
}
|
|
7536
|
+
});
|
|
7453
7537
|
}
|
|
7454
7538
|
}
|
|
7455
7539
|
return dataMap;
|
|
7456
7540
|
}
|
|
7541
|
+
function positiveInteger(value, fallback) {
|
|
7542
|
+
return value !== undefined && Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
7543
|
+
}
|
|
7457
7544
|
async function buildListUsersDataMap(dataProvider, requirements) {
|
|
7458
7545
|
const dataMap = new Map;
|
|
7459
7546
|
for (const req of requirements) {
|
|
@@ -14326,7 +14413,7 @@ async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
|
|
|
14326
14413
|
registry.register(ast);
|
|
14327
14414
|
const parse2 = async (source) => registry.register(await options.parse(source));
|
|
14328
14415
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
14329
|
-
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath),
|
|
14416
|
+
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath, options.paginationState),
|
|
14330
14417
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
14331
14418
|
buildTagCloudDataMap(dataProvider, options.requirements.tagCloud ?? [])
|
|
14332
14419
|
]);
|
|
@@ -14414,9 +14501,9 @@ async function resolveListPagesAsync(module, data, template, parse2) {
|
|
|
14414
14501
|
continue;
|
|
14415
14502
|
const variableContext = {
|
|
14416
14503
|
page,
|
|
14417
|
-
index: i + 1,
|
|
14504
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
14418
14505
|
total: data.totalCount,
|
|
14419
|
-
limit: module.limit,
|
|
14506
|
+
limit: data.pagination ? data.pagination.limit : module.limit,
|
|
14420
14507
|
site: data.site
|
|
14421
14508
|
};
|
|
14422
14509
|
const parsed = await parse2(template(variableContext));
|
|
@@ -14436,6 +14523,7 @@ async function resolveListPagesAsync(module, data, template, parse2) {
|
|
|
14436
14523
|
if (module["append-line"] && !module.separate) {
|
|
14437
14524
|
result.push(...(await parse2(module["append-line"])).elements);
|
|
14438
14525
|
}
|
|
14526
|
+
result.push(...createListPagesPager(data));
|
|
14439
14527
|
return module.wrapper ? [
|
|
14440
14528
|
{
|
|
14441
14529
|
element: "container",
|
|
@@ -14536,6 +14624,9 @@ async function processWikitext(source, options) {
|
|
|
14536
14624
|
const dataProvider = createModuleDataProvider(options, callbackContext);
|
|
14537
14625
|
const parseFragment = parseSource2;
|
|
14538
14626
|
let ast = initial.ast;
|
|
14627
|
+
const paginationState = { nextUnprefixed: 1 };
|
|
14628
|
+
const requestedPath = options.page.urlPath;
|
|
14629
|
+
const urlPath = !requestedPath || /^\/(?:[?#]|$)/.test(requestedPath) ? `/${options.page.fullName}${requestedPath?.slice(1) ?? ""}` : requestedPath;
|
|
14539
14630
|
for (let pass = 0;pass < DEFAULT_MODULE_MAX_PASSES; pass++) {
|
|
14540
14631
|
const extraction = extractDataRequirements(ast);
|
|
14541
14632
|
if (pass > 0 && !hasResolvableRequirements(extraction.requirements, options.dataProvider)) {
|
|
@@ -14546,7 +14637,8 @@ async function processWikitext(source, options) {
|
|
|
14546
14637
|
compiledListPagesTemplates: extraction.compiledListPagesTemplates,
|
|
14547
14638
|
compiledListUsersTemplates: extraction.compiledListUsersTemplates,
|
|
14548
14639
|
requirements: extraction.requirements,
|
|
14549
|
-
urlPath
|
|
14640
|
+
urlPath,
|
|
14641
|
+
paginationState,
|
|
14550
14642
|
pageTags: options.page.tags
|
|
14551
14643
|
});
|
|
14552
14644
|
ast = resolved.ast;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdprlib/parser",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Parser for Wikidot markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast",
|
|
@@ -44,6 +44,6 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@braintree/sanitize-url": "^7.1.1",
|
|
47
|
-
"@wdprlib/ast": "4.
|
|
47
|
+
"@wdprlib/ast": "4.2.0"
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -5,7 +5,7 @@ export const buildInfo: Readonly<{
|
|
|
5
5
|
sha: string | null;
|
|
6
6
|
dirty: boolean | null;
|
|
7
7
|
}> = Object.freeze({
|
|
8
|
-
version: "5.
|
|
9
|
-
sha: "
|
|
8
|
+
version: "5.3.0",
|
|
9
|
+
sha: "b71b84c705e05717f5ea12fd89684a91b669dbff",
|
|
10
10
|
dirty: false,
|
|
11
11
|
});
|
|
@@ -17,9 +17,9 @@ export function renderListPagesItems(
|
|
|
17
17
|
|
|
18
18
|
const ctx: VariableContext = {
|
|
19
19
|
page,
|
|
20
|
-
index: i + 1,
|
|
20
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
21
21
|
total: data.totalCount,
|
|
22
|
-
limit: module.limit,
|
|
22
|
+
limit: data.pagination ? data.pagination.limit : module.limit,
|
|
23
23
|
site: data.site,
|
|
24
24
|
};
|
|
25
25
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Element } from "@wdprlib/ast";
|
|
2
|
+
import type { ListPagesExternalData } from "../types";
|
|
3
|
+
|
|
4
|
+
export function createListPagesPager(data: ListPagesExternalData): Element[] {
|
|
5
|
+
const pagination = data.pagination;
|
|
6
|
+
if (!pagination || pagination.totalPages <= 1) return [];
|
|
7
|
+
const { currentPage, totalPages, urlPath, parameter } = pagination;
|
|
8
|
+
const pages = new Set([1, totalPages]);
|
|
9
|
+
for (
|
|
10
|
+
let page = Math.max(1, currentPage - 2);
|
|
11
|
+
page <= Math.min(totalPages, currentPage + 2);
|
|
12
|
+
page++
|
|
13
|
+
) {
|
|
14
|
+
pages.add(page);
|
|
15
|
+
}
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
element: "pager",
|
|
19
|
+
data: {
|
|
20
|
+
currentPage,
|
|
21
|
+
totalPages,
|
|
22
|
+
pages: [...pages]
|
|
23
|
+
.sort((a, b) => a - b)
|
|
24
|
+
.map((page) => ({
|
|
25
|
+
page,
|
|
26
|
+
href: pageUrl(urlPath, parameter, page),
|
|
27
|
+
})),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function pageUrl(urlPath: string, parameter: string, page: number): string {
|
|
34
|
+
const suffixStart = urlPath.search(/[?#]/);
|
|
35
|
+
const path = suffixStart === -1 ? urlPath : urlPath.slice(0, suffixStart);
|
|
36
|
+
const suffix = suffixStart === -1 ? "" : urlPath.slice(suffixStart);
|
|
37
|
+
const parts = path.split("/");
|
|
38
|
+
const result = parts.slice(0, 2);
|
|
39
|
+
for (let index = 2; index < parts.length; index += 2) {
|
|
40
|
+
if (parts[index] !== parameter) result.push(...parts.slice(index, index + 2));
|
|
41
|
+
}
|
|
42
|
+
return `${result.join("/").replace(/\/$/, "")}/${parameter}/${page}${suffix}`;
|
|
43
|
+
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { Element } from "@wdprlib/ast";
|
|
2
2
|
import { getModuleParseAst, type ParseFunction } from "../../types";
|
|
3
3
|
import type { ListPagesModuleData } from "../resolve";
|
|
4
|
+
import type { ListPagesExternalData } from "../types";
|
|
5
|
+
import { createListPagesPager } from "./pager";
|
|
4
6
|
|
|
5
7
|
export function wrapListPagesResult(
|
|
6
8
|
module: ListPagesModuleData,
|
|
7
9
|
items: Element[],
|
|
8
10
|
parse: ParseFunction,
|
|
11
|
+
data?: ListPagesExternalData,
|
|
9
12
|
): Element[] {
|
|
10
|
-
if (items.length === 0) {
|
|
13
|
+
if (items.length === 0 && (!data || data.pages.length === 0)) {
|
|
11
14
|
return [];
|
|
12
15
|
}
|
|
13
16
|
|
|
@@ -25,6 +28,8 @@ export function wrapListPagesResult(
|
|
|
25
28
|
result.push(...appendAst.elements);
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
if (data) result.push(...createListPagesPager(data));
|
|
32
|
+
|
|
28
33
|
if (module.wrapper) {
|
|
29
34
|
return [
|
|
30
35
|
{
|
|
@@ -56,5 +56,5 @@ export function resolveListPages(
|
|
|
56
56
|
parse: ParseFunction,
|
|
57
57
|
): Element[] {
|
|
58
58
|
const items = renderListPagesItems(module, data, compiledTemplate, parse);
|
|
59
|
-
return wrapListPagesResult(module, items, parse);
|
|
59
|
+
return wrapListPagesResult(module, items, parse, data);
|
|
60
60
|
}
|
|
@@ -94,6 +94,19 @@ export interface SiteContext {
|
|
|
94
94
|
*/
|
|
95
95
|
export interface ListPagesExternalData {
|
|
96
96
|
pages: PageData[];
|
|
97
|
+
/** Matching items before offset and limit; use the same visibility filters as pages. */
|
|
97
98
|
totalCount: number;
|
|
98
99
|
site: SiteContext;
|
|
100
|
+
/** Filled by module resolution when a page URL is available. */
|
|
101
|
+
pagination?: {
|
|
102
|
+
currentPage: number;
|
|
103
|
+
perPage: number;
|
|
104
|
+
totalPages: number;
|
|
105
|
+
/** Actual fetch offset, including the module's starting offset. */
|
|
106
|
+
offset: number;
|
|
107
|
+
/** Total item limit after URL resolution, not the fetch batch size. */
|
|
108
|
+
limit?: number;
|
|
109
|
+
urlPath: string;
|
|
110
|
+
parameter: string;
|
|
111
|
+
};
|
|
99
112
|
}
|
|
@@ -2,12 +2,13 @@ import { URL_RESOLVABLE_FIELDS } from "./fields";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Parse URL path parameters like /offset/1/page2_limit/1.
|
|
5
|
-
* Returns a map of parameter name -> value.
|
|
5
|
+
* Returns a map of parameter name -> value. Set hasPageName for a full page path;
|
|
6
|
+
* otherwise the legacy parameter-only-path heuristic is used.
|
|
6
7
|
*/
|
|
7
|
-
export function parseUrlParams(url: string): Map<string, string> {
|
|
8
|
+
export function parseUrlParams(url: string, hasPageName = false): Map<string, string> {
|
|
8
9
|
const params = new Map<string, string>();
|
|
9
|
-
const parts = url.split("/").filter(Boolean);
|
|
10
|
-
const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
|
|
10
|
+
const parts = url.split(/[?#]/, 1)[0]!.split("/").filter(Boolean);
|
|
11
|
+
const pairStart = !hasPageName && isUrlParameter(parts[0]) ? 0 : 1;
|
|
11
12
|
|
|
12
13
|
// Skip the page name (first part), parse key/value pairs.
|
|
13
14
|
for (let i = pairStart; i < parts.length - 1; i += 2) {
|
|
@@ -4,25 +4,97 @@ import type { ListUsersDataRequirement, ListUsersExternalData } from "../listuse
|
|
|
4
4
|
import type { TagCloudDataRequirement, TagCloudExternalData } from "../tagcloud/types";
|
|
5
5
|
import { parseUrlParams, resolveAndNormalizeQuery } from "../listpages/url-resolver";
|
|
6
6
|
|
|
7
|
+
export interface ListPagesPaginationState {
|
|
8
|
+
nextUnprefixed: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
export async function buildListPagesDataMap(
|
|
8
12
|
dataProvider: DataProvider,
|
|
9
13
|
requirements: ListPagesDataRequirement[],
|
|
10
14
|
urlPath: string | undefined,
|
|
15
|
+
paginationState: ListPagesPaginationState = { nextUnprefixed: 1 },
|
|
11
16
|
): Promise<Map<number, ListPagesExternalData>> {
|
|
12
17
|
const dataMap = new Map<number, ListPagesExternalData>();
|
|
13
|
-
const urlParams = parseUrlParams(urlPath ?? "");
|
|
18
|
+
const urlParams = parseUrlParams(urlPath ?? "", true);
|
|
14
19
|
|
|
15
20
|
for (const req of requirements) {
|
|
16
21
|
const normalizedQuery = resolveAndNormalizeQuery(req, urlParams);
|
|
17
|
-
|
|
22
|
+
if (!urlPath || !urlPath.startsWith("/") || urlPath.startsWith("//")) {
|
|
23
|
+
const data = await dataProvider.fetchListPages?.(normalizedQuery, req);
|
|
24
|
+
if (data) dataMap.set(req.id, data);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const ordinal = req.urlAttrPrefix ? 0 : paginationState.nextUnprefixed++;
|
|
28
|
+
const parameter = req.urlAttrPrefix
|
|
29
|
+
? `${encodeURIComponent(req.urlAttrPrefix)}_p`
|
|
30
|
+
: ordinal === 1
|
|
31
|
+
? "p"
|
|
32
|
+
: `p${ordinal}`;
|
|
33
|
+
const perPage = Math.min(250, positiveInteger(normalizedQuery.perPage, 20));
|
|
34
|
+
const baseOffset = positiveInteger(normalizedQuery.offset, 0);
|
|
35
|
+
const limit =
|
|
36
|
+
normalizedQuery.limit !== undefined && normalizedQuery.limit >= 0
|
|
37
|
+
? Math.floor(normalizedQuery.limit)
|
|
38
|
+
: undefined;
|
|
39
|
+
const rawPage = urlParams.get(parameter) ?? "1";
|
|
40
|
+
let currentPage = /^\d+$/.test(rawPage) ? positiveInteger(Number(rawPage), 1) : 1;
|
|
41
|
+
currentPage = Math.min(
|
|
42
|
+
currentPage,
|
|
43
|
+
Math.floor((Number.MAX_SAFE_INTEGER - baseOffset) / perPage) + 1,
|
|
44
|
+
);
|
|
45
|
+
if (limit !== undefined)
|
|
46
|
+
currentPage = Math.min(currentPage, Math.max(1, Math.ceil(limit / perPage)));
|
|
47
|
+
const fetchPage = () => {
|
|
48
|
+
const relativeOffset = (currentPage - 1) * perPage;
|
|
49
|
+
return dataProvider.fetchListPages?.(
|
|
50
|
+
{
|
|
51
|
+
...normalizedQuery,
|
|
52
|
+
offset: baseOffset + relativeOffset,
|
|
53
|
+
limit: Math.min(
|
|
54
|
+
perPage,
|
|
55
|
+
limit === undefined ? perPage : Math.max(0, limit - relativeOffset),
|
|
56
|
+
),
|
|
57
|
+
perPage,
|
|
58
|
+
},
|
|
59
|
+
req,
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
let data = await fetchPage();
|
|
18
63
|
if (data) {
|
|
19
|
-
|
|
64
|
+
const count = Math.min(Math.max(0, data.totalCount - baseOffset), limit ?? Infinity);
|
|
65
|
+
const totalPages = Math.ceil(count / perPage);
|
|
66
|
+
const lastPage = Math.max(1, totalPages);
|
|
67
|
+
if (currentPage > lastPage) {
|
|
68
|
+
currentPage = lastPage;
|
|
69
|
+
data = await fetchPage();
|
|
70
|
+
}
|
|
71
|
+
if (data)
|
|
72
|
+
dataMap.set(req.id, {
|
|
73
|
+
...data,
|
|
74
|
+
pages: data.pages.slice(
|
|
75
|
+
0,
|
|
76
|
+
Math.min(perPage, Math.max(0, count - (currentPage - 1) * perPage)),
|
|
77
|
+
),
|
|
78
|
+
pagination: {
|
|
79
|
+
currentPage,
|
|
80
|
+
perPage,
|
|
81
|
+
totalPages,
|
|
82
|
+
offset: baseOffset + (currentPage - 1) * perPage,
|
|
83
|
+
limit,
|
|
84
|
+
urlPath,
|
|
85
|
+
parameter,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
20
88
|
}
|
|
21
89
|
}
|
|
22
90
|
|
|
23
91
|
return dataMap;
|
|
24
92
|
}
|
|
25
93
|
|
|
94
|
+
function positiveInteger(value: number | undefined, fallback: number): number {
|
|
95
|
+
return value !== undefined && Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
96
|
+
}
|
|
97
|
+
|
|
26
98
|
export async function buildListUsersDataMap(
|
|
27
99
|
dataProvider: DataProvider,
|
|
28
100
|
requirements: ListUsersDataRequirement[],
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
import { buildListPagesDataMap, buildListUsersDataMap, buildTagCloudDataMap } from "./data-maps";
|
|
27
27
|
import { ModuleDocumentRegistry } from "./document";
|
|
28
28
|
import { collectStyles, mergeCollectedStyles } from "./styles";
|
|
29
|
+
import { createListPagesPager } from "../listpages/resolution/pager";
|
|
30
|
+
import type { ListPagesPaginationState } from "./data-maps";
|
|
29
31
|
|
|
30
32
|
export type AsyncModuleParseFunction = (source: string) => Promise<ModuleParseResult>;
|
|
31
33
|
|
|
@@ -40,6 +42,7 @@ export interface ResolveModulesWithAsyncParseOptions {
|
|
|
40
42
|
};
|
|
41
43
|
urlPath?: string;
|
|
42
44
|
pageTags: string[];
|
|
45
|
+
paginationState?: ListPagesPaginationState;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export interface AsyncModuleResolutionResult {
|
|
@@ -73,7 +76,12 @@ export async function resolveModulesWithAsyncParse(
|
|
|
73
76
|
registry.register(await options.parse(source));
|
|
74
77
|
|
|
75
78
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
76
|
-
buildListPagesDataMap(
|
|
79
|
+
buildListPagesDataMap(
|
|
80
|
+
dataProvider,
|
|
81
|
+
options.requirements.listPages ?? [],
|
|
82
|
+
options.urlPath,
|
|
83
|
+
options.paginationState,
|
|
84
|
+
),
|
|
77
85
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
78
86
|
buildTagCloudDataMap(dataProvider, options.requirements.tagCloud ?? []),
|
|
79
87
|
]);
|
|
@@ -175,9 +183,9 @@ async function resolveListPagesAsync(
|
|
|
175
183
|
if (!page) continue;
|
|
176
184
|
const variableContext: VariableContext = {
|
|
177
185
|
page,
|
|
178
|
-
index: i + 1,
|
|
186
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
179
187
|
total: data.totalCount,
|
|
180
|
-
limit: module.limit,
|
|
188
|
+
limit: data.pagination ? data.pagination.limit : module.limit,
|
|
181
189
|
site: data.site,
|
|
182
190
|
};
|
|
183
191
|
const parsed = await parse(template(variableContext));
|
|
@@ -197,6 +205,7 @@ async function resolveListPagesAsync(
|
|
|
197
205
|
if (module["append-line"] && !module.separate) {
|
|
198
206
|
result.push(...(await parse(module["append-line"])).elements);
|
|
199
207
|
}
|
|
208
|
+
result.push(...createListPagesPager(data));
|
|
200
209
|
|
|
201
210
|
return module.wrapper
|
|
202
211
|
? [
|
package/src/pipeline/process.ts
CHANGED
|
@@ -82,6 +82,12 @@ export async function processWikitext<TPage extends WikitextPageContext>(
|
|
|
82
82
|
const dataProvider = createModuleDataProvider(options, callbackContext);
|
|
83
83
|
const parseFragment = parseSource;
|
|
84
84
|
let ast = initial.ast;
|
|
85
|
+
const paginationState = { nextUnprefixed: 1 };
|
|
86
|
+
const requestedPath = options.page.urlPath;
|
|
87
|
+
const urlPath =
|
|
88
|
+
!requestedPath || /^\/(?:[?#]|$)/.test(requestedPath)
|
|
89
|
+
? `/${options.page.fullName}${requestedPath?.slice(1) ?? ""}`
|
|
90
|
+
: requestedPath;
|
|
85
91
|
|
|
86
92
|
for (let pass = 0; pass < DEFAULT_MODULE_MAX_PASSES; pass++) {
|
|
87
93
|
const extraction = extractDataRequirements(ast);
|
|
@@ -94,7 +100,8 @@ export async function processWikitext<TPage extends WikitextPageContext>(
|
|
|
94
100
|
compiledListPagesTemplates: extraction.compiledListPagesTemplates,
|
|
95
101
|
compiledListUsersTemplates: extraction.compiledListUsersTemplates,
|
|
96
102
|
requirements: extraction.requirements,
|
|
97
|
-
urlPath
|
|
103
|
+
urlPath,
|
|
104
|
+
paginationState,
|
|
98
105
|
pageTags: options.page.tags,
|
|
99
106
|
});
|
|
100
107
|
ast = resolved.ast;
|