@wdprlib/parser 4.4.0 → 5.1.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.js CHANGED
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  createPoint,
4
4
  createPosition,
5
- text,
5
+ text as text2,
6
6
  container,
7
- paragraph,
7
+ paragraph as paragraph2,
8
8
  bold,
9
9
  italics,
10
10
  heading,
11
- lineBreak,
11
+ lineBreak as lineBreak2,
12
12
  horizontalRule,
13
13
  link,
14
14
  list,
@@ -5856,6 +5856,60 @@ function resolveListPages(module, data, compiledTemplate, parse) {
5856
5856
  const items = renderListPagesItems(module, data, compiledTemplate, parse);
5857
5857
  return wrapListPagesResult(module, items, parse);
5858
5858
  }
5859
+ // packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
5860
+ function definePageData(input) {
5861
+ const separator = input.fullname.indexOf(":");
5862
+ const category = separator === -1 ? "_default" : input.fullname.slice(0, separator);
5863
+ const name = separator === -1 ? input.fullname : input.fullname.slice(separator + 1);
5864
+ return {
5865
+ ...input,
5866
+ name: input.name ?? name,
5867
+ category: input.category ?? category,
5868
+ hiddenTags: input.hiddenTags ?? [],
5869
+ children: input.children ?? 0,
5870
+ comments: input.comments ?? 0,
5871
+ size: input.size ?? 0,
5872
+ rating: input.rating ?? 0,
5873
+ ratingVotes: input.ratingVotes ?? 0,
5874
+ revisions: input.revisions ?? 0
5875
+ };
5876
+ }
5877
+ // packages/parser/src/parser/rules/block/module/listpages/selectors.ts
5878
+ function matchesListPagesSelectors(page, query, currentPage) {
5879
+ return matchesCategory(page.category, query.category, currentPage.category) && matchesTags(page, query.tags, currentPage);
5880
+ }
5881
+ function matchesCategory(category, selector, currentCategory) {
5882
+ if (!selector)
5883
+ return category === currentCategory;
5884
+ if (selector.exclude.includes(category))
5885
+ return false;
5886
+ const hasPositiveSelector = selector.all || selector.current || selector.include.length > 0;
5887
+ return !hasPositiveSelector || selector.all || selector.current && category === currentCategory || selector.include.includes(category);
5888
+ }
5889
+ function matchesTags(page, selector, currentPage) {
5890
+ if (!selector)
5891
+ return true;
5892
+ const allTags = new Set([...page.tags, ...page.hiddenTags]);
5893
+ if (selector.all.some((tag) => !allTags.has(tag)))
5894
+ return false;
5895
+ if (selector.any.length > 0 && !selector.any.some((tag) => allTags.has(tag)))
5896
+ return false;
5897
+ if (selector.none.some((tag) => allTags.has(tag)))
5898
+ return false;
5899
+ if (selector.special === "none")
5900
+ return allTags.size === 0;
5901
+ const currentTags = new Set(currentPage.tags.filter((tag) => !tag.startsWith("_")));
5902
+ if (selector.special === "same-visible") {
5903
+ return page.tags.some((tag) => currentTags.has(tag));
5904
+ }
5905
+ if (selector.special === "same-all") {
5906
+ return setsEqual(new Set(page.tags), currentTags);
5907
+ }
5908
+ return true;
5909
+ }
5910
+ function setsEqual(left, right) {
5911
+ return left.size === right.size && [...left].every((value) => right.has(value));
5912
+ }
5859
5913
  // packages/parser/src/parser/rules/block/module/listpages/url-resolution/fields.ts
5860
5914
  var URL_RESOLVABLE_FIELDS = [
5861
5915
  { attr: "offset", queryKey: "offset", type: "number" },
@@ -6285,13 +6339,20 @@ var BASE_PLACEHOLDER_OPEN = "";
6285
6339
  var BASE_PLACEHOLDER_CLOSE = "";
6286
6340
  var RAW_BLOCK_OPEN_PATTERN = /\[\[\s*(code|html)\b[^\]]*\]\]/iy;
6287
6341
  function makeUniqueSentinels(source) {
6288
- let open = BASE_PLACEHOLDER_OPEN;
6289
- let close = BASE_PLACEHOLDER_CLOSE;
6290
- while (source.includes(open) || source.includes(close)) {
6291
- open += BASE_PLACEHOLDER_OPEN;
6292
- close += BASE_PLACEHOLDER_CLOSE;
6342
+ let openRun = 0;
6343
+ let closeRun = 0;
6344
+ let longestOpenRun = 0;
6345
+ let longestCloseRun = 0;
6346
+ for (const char of source) {
6347
+ openRun = char === BASE_PLACEHOLDER_OPEN ? openRun + 1 : 0;
6348
+ closeRun = char === BASE_PLACEHOLDER_CLOSE ? closeRun + 1 : 0;
6349
+ longestOpenRun = Math.max(longestOpenRun, openRun);
6350
+ longestCloseRun = Math.max(longestCloseRun, closeRun);
6293
6351
  }
6294
- return { open, close };
6352
+ return {
6353
+ open: BASE_PLACEHOLDER_OPEN.repeat(longestOpenRun + 1),
6354
+ close: BASE_PLACEHOLDER_CLOSE.repeat(longestCloseRun + 1)
6355
+ };
6295
6356
  }
6296
6357
  function maskRawRegions(source, sentinels) {
6297
6358
  const placeholders = [];
@@ -6529,13 +6590,40 @@ function scanIncludeDirectives(source) {
6529
6590
  `, start);
6530
6591
  let depth = 0;
6531
6592
  let linkDepth = 0;
6593
+ const nestedQuotes = [];
6594
+ const nestedQuoteAllowed = [];
6532
6595
  let i = start;
6533
6596
  let closeEnd = -1;
6534
6597
  while (i < source.length) {
6535
6598
  const ch = source.charCodeAt(i);
6536
6599
  const next = source.charCodeAt(i + 1);
6537
6600
  const nextNext = source.charCodeAt(i + 2);
6538
- if (ch === OPEN_BRACKET && next === OPEN_BRACKET && nextNext === OPEN_BRACKET) {
6601
+ if (ch === 10 || ch === 13) {
6602
+ linkDepth = 0;
6603
+ if (depth > 1) {
6604
+ depth = 1;
6605
+ nestedQuotes.length = 0;
6606
+ nestedQuoteAllowed.length = 0;
6607
+ }
6608
+ i++;
6609
+ continue;
6610
+ }
6611
+ const nestedQuote = nestedQuotes.at(-1);
6612
+ if (nestedQuote !== undefined && nestedQuote !== null) {
6613
+ if (ch === 92) {
6614
+ i += 2;
6615
+ } else {
6616
+ if (ch === nestedQuote) {
6617
+ nestedQuotes[nestedQuotes.length - 1] = null;
6618
+ nestedQuoteAllowed[nestedQuoteAllowed.length - 1] = false;
6619
+ }
6620
+ i++;
6621
+ }
6622
+ } else if (nestedQuote === null && nestedQuoteAllowed.at(-1) === true && (ch === 34 || ch === 39)) {
6623
+ nestedQuotes[nestedQuotes.length - 1] = ch;
6624
+ nestedQuoteAllowed[nestedQuoteAllowed.length - 1] = false;
6625
+ i++;
6626
+ } else if (ch === OPEN_BRACKET && next === OPEN_BRACKET && nextNext === OPEN_BRACKET) {
6539
6627
  linkDepth++;
6540
6628
  i += 3;
6541
6629
  } else if (linkDepth > 0 && ch === CLOSE_BRACKET && next === CLOSE_BRACKET && nextNext === CLOSE_BRACKET) {
@@ -6544,10 +6632,26 @@ function scanIncludeDirectives(source) {
6544
6632
  } else if (linkDepth > 0) {
6545
6633
  i++;
6546
6634
  } else if (ch === OPEN_BRACKET && next === OPEN_BRACKET) {
6635
+ if (nestedQuoteAllowed.length > 0) {
6636
+ nestedQuoteAllowed[nestedQuoteAllowed.length - 1] = false;
6637
+ }
6638
+ if (depth > 0) {
6639
+ nestedQuotes.push(null);
6640
+ nestedQuoteAllowed.push(false);
6641
+ }
6547
6642
  depth++;
6548
6643
  i += 2;
6644
+ } else if (ch === CLOSE_BRACKET && next !== CLOSE_BRACKET && depth > 1) {
6645
+ depth--;
6646
+ nestedQuotes.pop();
6647
+ nestedQuoteAllowed.pop();
6648
+ i++;
6549
6649
  } else if (ch === CLOSE_BRACKET && next === CLOSE_BRACKET) {
6550
6650
  const closeStart = i;
6651
+ if (depth > 1) {
6652
+ nestedQuotes.pop();
6653
+ nestedQuoteAllowed.pop();
6654
+ }
6551
6655
  depth--;
6552
6656
  i += 2;
6553
6657
  if (depth <= 0) {
@@ -6564,6 +6668,13 @@ function scanIncludeDirectives(source) {
6564
6668
  }
6565
6669
  }
6566
6670
  } else {
6671
+ if (nestedQuoteAllowed.length > 0) {
6672
+ if (ch === 61) {
6673
+ nestedQuoteAllowed[nestedQuoteAllowed.length - 1] = true;
6674
+ } else if (ch !== 32 && ch !== 9) {
6675
+ nestedQuoteAllowed[nestedQuoteAllowed.length - 1] = false;
6676
+ }
6677
+ }
6567
6678
  i++;
6568
6679
  }
6569
6680
  }
@@ -6749,13 +6860,13 @@ function expandIterativeWithTrace(source, fetcher, maxIterations) {
6749
6860
  reachedMaxIterations: iterations.length === maxIterations && scanIncludeDirectives(current2).length > 0
6750
6861
  };
6751
6862
  }
6752
- async function expandIterativeAsyncWithTrace(source, fetcher, maxIterations) {
6863
+ async function expandIterativeAsyncWithTrace(source, fetcher, maxIterations, shouldDefer) {
6753
6864
  let current2 = source;
6754
6865
  const replacementCache = new Map;
6755
6866
  const dependencies = [];
6756
6867
  const iterations = [];
6757
6868
  for (let i = 0;i < maxIterations; i++) {
6758
- const expanded = await expandOneIterationAsyncWithTrace(current2, fetcher, replacementCache, i);
6869
+ const expanded = await expandOneIterationAsyncWithTrace(current2, fetcher, replacementCache, i, shouldDefer);
6759
6870
  if (expanded === null)
6760
6871
  break;
6761
6872
  dependencies.push(...expanded.dependencies);
@@ -6772,7 +6883,7 @@ async function expandIterativeAsyncWithTrace(source, fetcher, maxIterations) {
6772
6883
  source: current2,
6773
6884
  dependencies,
6774
6885
  iterations,
6775
- reachedMaxIterations: iterations.length === maxIterations && scanIncludeDirectives(current2).length > 0
6886
+ reachedMaxIterations: iterations.length === maxIterations && hasResolvableDirectives(current2, shouldDefer)
6776
6887
  };
6777
6888
  }
6778
6889
  function expandOneIteration(source, fetcher, replacementCache) {
@@ -6811,14 +6922,15 @@ function expandOneIterationWithTrace(source, fetcher, replacementCache, iteratio
6811
6922
  dependencies
6812
6923
  };
6813
6924
  }
6814
- async function expandOneIterationAsyncWithTrace(source, fetcher, replacementCache, iteration) {
6925
+ async function expandOneIterationAsyncWithTrace(source, fetcher, replacementCache, iteration, shouldDefer) {
6815
6926
  if (!MAYBE_INCLUDE_PATTERN.test(source))
6816
6927
  return null;
6817
6928
  const directives = scanIncludeDirectives(source);
6818
6929
  if (directives.length === 0)
6819
6930
  return null;
6820
6931
  const references = directives.map(createIncludeReference);
6821
- const replacements = await Promise.all(directives.map(({ inner }) => replaceCachedAsync(inner, fetcher, replacementCache)));
6932
+ const deferred = references.map((reference) => shouldDefer?.(reference) ?? false);
6933
+ const replacements = await Promise.all(directives.map((directive, index) => deferred[index] ? Promise.resolve(source.slice(directive.start, directive.end)) : replaceCachedAsync(directive.inner, fetcher, replacementCache)));
6822
6934
  const parts = [];
6823
6935
  let lastPos = 0;
6824
6936
  for (let i = 0;i < directives.length; i++) {
@@ -6830,9 +6942,15 @@ async function expandOneIterationAsyncWithTrace(source, fetcher, replacementCach
6830
6942
  return {
6831
6943
  source: parts.join(""),
6832
6944
  references,
6833
- dependencies: references.map((reference) => ({ ...reference, iteration }))
6945
+ dependencies: references.filter((_, index) => !deferred[index]).map((reference) => ({ ...reference, iteration }))
6834
6946
  };
6835
6947
  }
6948
+ function hasResolvableDirectives(source, shouldDefer) {
6949
+ const directives = scanIncludeDirectives(source);
6950
+ if (!shouldDefer)
6951
+ return directives.length > 0;
6952
+ return directives.some((directive) => !shouldDefer(createIncludeReference(directive)));
6953
+ }
6836
6954
  function replaceCached(inner, fetcher, cache) {
6837
6955
  const cached = cache.get(inner);
6838
6956
  if (cached !== undefined)
@@ -6888,6 +7006,19 @@ async function resolveIncludesAsyncWithTrace(source, fetcher, options) {
6888
7006
  const cachedFetcher = createCachedAsyncIncludeFetcher(fetcher, normalizePageKey);
6889
7007
  return expandIterativeAsyncWithTrace(source, cachedFetcher, maxIterations);
6890
7008
  }
7009
+ async function resolveIncludesAsyncWithTraceSelective(source, fetcher, shouldDefer, options) {
7010
+ if (options?.settings && !options.settings.enablePageSyntax) {
7011
+ return {
7012
+ source,
7013
+ dependencies: [],
7014
+ iterations: [],
7015
+ reachedMaxIterations: false
7016
+ };
7017
+ }
7018
+ const maxIterations = options?.maxIterations ?? 10;
7019
+ const cachedFetcher = createCachedAsyncIncludeFetcher(fetcher, normalizePageKey);
7020
+ return expandIterativeAsyncWithTrace(source, cachedFetcher, maxIterations, shouldDefer);
7021
+ }
6891
7022
  function normalizePageKey(location) {
6892
7023
  const site = location.site ?? "";
6893
7024
  const page = location.page.toLowerCase();
@@ -8358,6 +8489,9 @@ var tabviewRule = {
8358
8489
  }
8359
8490
  };
8360
8491
 
8492
+ // packages/parser/src/parser/rules/block/include/index.ts
8493
+ import { lineBreak, paragraph, text } from "@wdprlib/ast";
8494
+
8361
8495
  // packages/parser/src/parser/rules/block/include/arguments.ts
8362
8496
  function collectIncludeArguments(ctx, startPos) {
8363
8497
  const argumentTokens = [];
@@ -8473,6 +8607,7 @@ var includeRule = {
8473
8607
  }
8474
8608
  pos++;
8475
8609
  consumed++;
8610
+ const directiveEnd = pos;
8476
8611
  if (ctx.tokens[pos]?.type === "NEWLINE") {
8477
8612
  pos++;
8478
8613
  consumed++;
@@ -8480,6 +8615,20 @@ var includeRule = {
8480
8615
  if (!args.target) {
8481
8616
  return { success: false };
8482
8617
  }
8618
+ const location = parsePageRef(args.target);
8619
+ if (ctx.deferInclude?.(location)) {
8620
+ const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
8621
+ const elements = [];
8622
+ const lines = source.split(`
8623
+ `);
8624
+ for (let index = 0;index < lines.length; index++) {
8625
+ if (index > 0)
8626
+ elements.push(lineBreak());
8627
+ if (lines[index] !== "")
8628
+ elements.push(text(lines[index]));
8629
+ }
8630
+ return { success: true, elements: [paragraph(elements)], consumed };
8631
+ }
8483
8632
  return {
8484
8633
  success: true,
8485
8634
  elements: [
@@ -8488,7 +8637,7 @@ var includeRule = {
8488
8637
  data: {
8489
8638
  "paragraph-safe": false,
8490
8639
  variables: parseVariables(args.argumentTokens),
8491
- location: parsePageRef(args.target),
8640
+ location,
8492
8641
  elements: []
8493
8642
  }
8494
8643
  }
@@ -9756,9 +9905,9 @@ function parseGalleryItemLine(content) {
9756
9905
  const alt = attrs.get("alt") ?? null;
9757
9906
  return { source, link, alt, newWindow };
9758
9907
  }
9759
- function parseItemAttrs(text) {
9908
+ function parseItemAttrs(text2) {
9760
9909
  const attrs = new Map;
9761
- const parts = text.trim().split('="');
9910
+ const parts = text2.trim().split('="');
9762
9911
  let key = parts[0]?.trim() ?? "";
9763
9912
  for (let i = 1;i < parts.length; i++) {
9764
9913
  const val = parts[i] ?? "";
@@ -11820,11 +11969,11 @@ var guillemetRule = {
11820
11969
  startTokens: ["LEFT_DOUBLE_ANGLE", "RIGHT_DOUBLE_ANGLE"],
11821
11970
  parse(ctx) {
11822
11971
  const token5 = ctx.tokens[ctx.pos];
11823
- const text = guillemetText(token5?.type);
11824
- if (text) {
11972
+ const text2 = guillemetText(token5?.type);
11973
+ if (text2) {
11825
11974
  return {
11826
11975
  success: true,
11827
- elements: [{ element: "text", data: text }],
11976
+ elements: [{ element: "text", data: text2 }],
11828
11977
  consumed: 1
11829
11978
  };
11830
11979
  }
@@ -12782,7 +12931,7 @@ var inlineRules = [
12782
12931
  textRule
12783
12932
  ];
12784
12933
  // packages/parser/src/parser/parse/context.ts
12785
- function createParseContext(tokens, options = {}) {
12934
+ function createParseContext(tokens, options = {}, deferInclude) {
12786
12935
  return {
12787
12936
  tokens,
12788
12937
  pos: 0,
@@ -12790,6 +12939,7 @@ function createParseContext(tokens, options = {}) {
12790
12939
  trackPositions: options.trackPositions ?? true,
12791
12940
  settings: options.settings ?? DEFAULT_SETTINGS,
12792
12941
  appendImplicitFootnoteBlock: options.appendImplicitFootnoteBlock ?? true,
12942
+ deferInclude,
12793
12943
  footnotes: [],
12794
12944
  tocEntries: [],
12795
12945
  codeBlocks: [],
@@ -13366,39 +13516,41 @@ class Parser {
13366
13516
  this.ctx = createParseContext(tokens, options);
13367
13517
  }
13368
13518
  parse() {
13369
- const children = [];
13370
- while (!this.isAtEnd()) {
13371
- const blocks = this.parseBlock();
13372
- children.push(...blocks);
13373
- }
13374
- return finalizeParseResult(this.ctx, children);
13519
+ return parseContext(this.ctx);
13375
13520
  }
13376
- isAtEnd() {
13377
- return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
13378
- }
13379
- currentToken() {
13380
- return this.ctx.tokens[this.ctx.pos] ?? this.eofToken();
13381
- }
13382
- eofToken() {
13383
- return {
13384
- type: "EOF",
13385
- value: "",
13386
- position: {
13387
- start: { line: 0, column: 0, offset: 0 },
13388
- end: { line: 0, column: 0, offset: 0 }
13389
- },
13390
- lineStart: false
13391
- };
13392
- }
13393
- skipWhitespace() {
13394
- while (this.currentToken().type === "WHITESPACE") {
13395
- this.ctx.pos++;
13396
- }
13521
+ }
13522
+ function parseTokensWithIncludeDeferral(tokens, options, deferInclude) {
13523
+ return parseContext(createParseContext(tokens, options, deferInclude));
13524
+ }
13525
+ function parseContext(ctx) {
13526
+ const children = [];
13527
+ while (!isAtEnd3(ctx)) {
13528
+ children.push(...parseBlock(ctx));
13397
13529
  }
13398
- parseBlock() {
13399
- return parseNextBlock(this.ctx, () => this.skipWhitespace(), () => this.isAtEnd());
13530
+ return finalizeParseResult(ctx, children);
13531
+ }
13532
+ function isAtEnd3(ctx) {
13533
+ return ctx.pos >= ctx.tokens.length || currentToken2(ctx).type === "EOF";
13534
+ }
13535
+ function currentToken2(ctx) {
13536
+ return ctx.tokens[ctx.pos] ?? {
13537
+ type: "EOF",
13538
+ value: "",
13539
+ position: {
13540
+ start: { line: 0, column: 0, offset: 0 },
13541
+ end: { line: 0, column: 0, offset: 0 }
13542
+ },
13543
+ lineStart: false
13544
+ };
13545
+ }
13546
+ function skipWhitespace4(ctx) {
13547
+ while (currentToken2(ctx).type === "WHITESPACE") {
13548
+ ctx.pos++;
13400
13549
  }
13401
13550
  }
13551
+ function parseBlock(ctx) {
13552
+ return parseNextBlock(ctx, () => skipWhitespace4(ctx), () => isAtEnd3(ctx));
13553
+ }
13402
13554
 
13403
13555
  // packages/parser/src/parser/parse/plain-non-ascii.ts
13404
13556
  var LARGE_PLAIN_TEXT_MIN_LENGTH = 1e5;
@@ -13406,8 +13558,8 @@ function parsePlainNonAsciiDocument(source) {
13406
13558
  if (!isPlainNonAsciiDocument(source)) {
13407
13559
  return null;
13408
13560
  }
13409
- const text = trimNewlineEdges(source);
13410
- const elements = text === "" ? [] : buildPlainParagraphs(text);
13561
+ const text2 = trimNewlineEdges(source);
13562
+ const elements = text2 === "" ? [] : buildPlainParagraphs(text2);
13411
13563
  elements.push({
13412
13564
  element: "footnote-block",
13413
13565
  data: { title: null, hide: false }
@@ -13427,8 +13579,8 @@ function parseLargePlainTextDocument(source) {
13427
13579
  if (source.length < LARGE_PLAIN_TEXT_MIN_LENGTH || hasWikitextSyntaxCandidate(source)) {
13428
13580
  return null;
13429
13581
  }
13430
- const text = trimNewlineEdges(source);
13431
- const elements = text === "" ? [] : buildPlainParagraphs(text);
13582
+ const text2 = trimNewlineEdges(source);
13583
+ const elements = text2 === "" ? [] : buildPlainParagraphs(text2);
13432
13584
  elements.push({
13433
13585
  element: "footnote-block",
13434
13586
  data: { title: null, hide: false }
@@ -13493,10 +13645,10 @@ function trimNewlineEdges(source) {
13493
13645
  end--;
13494
13646
  return start === 0 && end === source.length ? source : source.slice(start, end);
13495
13647
  }
13496
- function buildPlainParagraphs(text) {
13497
- const paragraphs = text.indexOf(`
13648
+ function buildPlainParagraphs(text2) {
13649
+ const paragraphs = text2.indexOf(`
13498
13650
 
13499
- `) === -1 ? [text] : text.split(/\n{2,}/).filter((part) => part !== "");
13651
+ `) === -1 ? [text2] : text2.split(/\n{2,}/).filter((part) => part !== "");
13500
13652
  return paragraphs.map((paragraphText) => ({
13501
13653
  element: "container",
13502
13654
  data: {
@@ -13506,8 +13658,8 @@ function buildPlainParagraphs(text) {
13506
13658
  }
13507
13659
  }));
13508
13660
  }
13509
- function buildPlainParagraphElements(text) {
13510
- const lines = text.split(`
13661
+ function buildPlainParagraphElements(text2) {
13662
+ const lines = text2.split(`
13511
13663
  `);
13512
13664
  const elements = Array.from({ length: lines.length * 2 - 1 });
13513
13665
  let out = 0;
@@ -13521,32 +13673,32 @@ function buildPlainParagraphElements(text) {
13521
13673
  }
13522
13674
 
13523
13675
  // packages/parser/src/parser/preprocess/whitespace/detection.ts
13524
- function needsWhitespaceSubstitution(text) {
13525
- if (text.length === 0)
13676
+ function needsWhitespaceSubstitution(text2) {
13677
+ if (text2.length === 0)
13526
13678
  return false;
13527
- if (text[0] === `
13528
- ` || text[0] === " " || text[text.length - 1] === `
13679
+ if (text2[0] === `
13680
+ ` || text2[0] === " " || text2[text2.length - 1] === `
13529
13681
  `) {
13530
13682
  return true;
13531
13683
  }
13532
- return text.indexOf("\r") !== -1 || text.indexOf("\t") !== -1 || text.indexOf("\x00") !== -1 || text.indexOf(" ") !== -1 || text.indexOf(" ") !== -1 || text.indexOf("\\\n") !== -1 || text.indexOf(`
13684
+ return text2.indexOf("\r") !== -1 || text2.indexOf("\t") !== -1 || text2.indexOf("\x00") !== -1 || text2.indexOf(" ") !== -1 || text2.indexOf(" ") !== -1 || text2.indexOf("\\\n") !== -1 || text2.indexOf(`
13533
13685
 
13534
13686
 
13535
- `) !== -1 || text.indexOf(`
13687
+ `) !== -1 || text2.indexOf(`
13536
13688
  `) !== -1;
13537
13689
  }
13538
- function mayContainWhitespaceOnlyLine(text) {
13539
- const first = text[0];
13690
+ function mayContainWhitespaceOnlyLine(text2) {
13691
+ const first = text2[0];
13540
13692
  if (first === " " || first === "\t" || first === `
13541
13693
  ` || first === " " || first === " ") {
13542
13694
  return true;
13543
13695
  }
13544
- return text.indexOf(`
13545
- `) !== -1 || text.indexOf(`
13696
+ return text2.indexOf(`
13697
+ `) !== -1 || text2.indexOf(`
13546
13698
 
13547
- `) !== -1 || text.indexOf(`
13548
- `) !== -1 || text.indexOf(`
13549
-  `) !== -1 || text.indexOf(`
13699
+ `) !== -1 || text2.indexOf(`
13700
+ `) !== -1 || text2.indexOf(`
13701
+  `) !== -1 || text2.indexOf(`
13550
13702
   `) !== -1;
13551
13703
  }
13552
13704
 
@@ -13559,18 +13711,18 @@ var TABS = /\t/g;
13559
13711
  var NULL_CHARS = new RegExp(String.fromCharCode(0), "g");
13560
13712
 
13561
13713
  // packages/parser/src/parser/preprocess/whitespace/leading-spaces.ts
13562
- function replaceLeadingSpaces(text) {
13563
- return text.replace(LEADING_NONSTANDARD_WHITESPACE, (match) => {
13714
+ function replaceLeadingSpaces(text2) {
13715
+ return text2.replace(LEADING_NONSTANDARD_WHITESPACE, (match) => {
13564
13716
  return " ".repeat(match.length);
13565
13717
  });
13566
13718
  }
13567
13719
 
13568
13720
  // packages/parser/src/parser/preprocess/whitespace/index.ts
13569
- function substitute(text) {
13570
- if (!needsWhitespaceSubstitution(text)) {
13571
- return text;
13721
+ function substitute(text2) {
13722
+ if (!needsWhitespaceSubstitution(text2)) {
13723
+ return text2;
13572
13724
  }
13573
- let result = text;
13725
+ let result = text2;
13574
13726
  if (result.indexOf("\r") !== -1) {
13575
13727
  result = result.replace(DOS_MAC_NEWLINES, `
13576
13728
  `);
@@ -13600,21 +13752,21 @@ function substitute(text) {
13600
13752
  }
13601
13753
  return result;
13602
13754
  }
13603
- function trimLeadingNewlines(text) {
13755
+ function trimLeadingNewlines(text2) {
13604
13756
  let index = 0;
13605
- while (text[index] === `
13757
+ while (text2[index] === `
13606
13758
  `) {
13607
13759
  index++;
13608
13760
  }
13609
- return index === 0 ? text : text.slice(index);
13761
+ return index === 0 ? text2 : text2.slice(index);
13610
13762
  }
13611
- function trimTrailingNewlines(text) {
13612
- let end = text.length;
13613
- while (end > 0 && text[end - 1] === `
13763
+ function trimTrailingNewlines(text2) {
13764
+ let end = text2.length;
13765
+ while (end > 0 && text2[end - 1] === `
13614
13766
  `) {
13615
13767
  end--;
13616
13768
  }
13617
- return end === text.length ? text : text.slice(0, end);
13769
+ return end === text2.length ? text2 : text2.slice(0, end);
13618
13770
  }
13619
13771
 
13620
13772
  // packages/parser/src/parser/preprocess/typography.ts
@@ -13624,50 +13776,50 @@ var LEFT_DOUBLE_QUOTE = "“";
13624
13776
  var RIGHT_DOUBLE_QUOTE = "”";
13625
13777
  var LOW_DOUBLE_QUOTE = "„";
13626
13778
  var ELLIPSIS = "…";
13627
- function replaceExactEllipsisPattern(text, pattern) {
13779
+ function replaceExactEllipsisPattern(text2, pattern) {
13628
13780
  let searchFrom = 0;
13629
13781
  let result = "";
13630
13782
  let lastCopied = 0;
13631
13783
  const patternLength = pattern.length;
13632
- while (searchFrom < text.length) {
13633
- const index = text.indexOf(pattern, searchFrom);
13784
+ while (searchFrom < text2.length) {
13785
+ const index = text2.indexOf(pattern, searchFrom);
13634
13786
  if (index === -1)
13635
13787
  break;
13636
- const prev = index > 0 ? text[index - 1] : "";
13637
- const next = index + patternLength < text.length ? text[index + patternLength] : "";
13788
+ const prev = index > 0 ? text2[index - 1] : "";
13789
+ const next = index + patternLength < text2.length ? text2[index + patternLength] : "";
13638
13790
  if (prev !== "." && next !== ".") {
13639
- result += text.slice(lastCopied, index) + ELLIPSIS;
13791
+ result += text2.slice(lastCopied, index) + ELLIPSIS;
13640
13792
  lastCopied = index + patternLength;
13641
13793
  searchFrom = lastCopied;
13642
13794
  } else {
13643
13795
  searchFrom = index + 1;
13644
13796
  }
13645
13797
  }
13646
- return lastCopied === 0 ? text : result + text.slice(lastCopied);
13798
+ return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
13647
13799
  }
13648
- function replaceDelimitedTypography(text, opener, closer, leftQuote, rightQuote) {
13800
+ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote) {
13649
13801
  let searchFrom = 0;
13650
13802
  let result = "";
13651
13803
  let lastCopied = 0;
13652
- while (searchFrom < text.length) {
13653
- const openIndex = text.indexOf(opener, searchFrom);
13804
+ while (searchFrom < text2.length) {
13805
+ const openIndex = text2.indexOf(opener, searchFrom);
13654
13806
  if (openIndex === -1)
13655
13807
  break;
13656
13808
  const contentStart = openIndex + opener.length;
13657
- const closeIndex = text.indexOf(closer, contentStart);
13809
+ const closeIndex = text2.indexOf(closer, contentStart);
13658
13810
  if (closeIndex === -1)
13659
13811
  break;
13660
- result += text.slice(lastCopied, openIndex);
13812
+ result += text2.slice(lastCopied, openIndex);
13661
13813
  result += leftQuote;
13662
- result += text.slice(contentStart, closeIndex);
13814
+ result += text2.slice(contentStart, closeIndex);
13663
13815
  result += rightQuote;
13664
13816
  lastCopied = closeIndex + closer.length;
13665
13817
  searchFrom = lastCopied;
13666
13818
  }
13667
- return lastCopied === 0 ? text : result + text.slice(lastCopied);
13819
+ return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
13668
13820
  }
13669
- function substitute2(text) {
13670
- let result = text;
13821
+ function substitute2(text2) {
13822
+ let result = text2;
13671
13823
  if (result.includes("``") && result.includes("''")) {
13672
13824
  result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
13673
13825
  }
@@ -13687,37 +13839,13 @@ function substitute2(text) {
13687
13839
  }
13688
13840
 
13689
13841
  // packages/parser/src/parser/preprocess/index.ts
13690
- function preprocess(text) {
13691
- let result = text;
13842
+ function preprocess(text2) {
13843
+ let result = text2;
13692
13844
  result = substitute(result);
13693
13845
  result = substitute2(result);
13694
13846
  return result;
13695
13847
  }
13696
13848
 
13697
- // packages/parser/src/parser/preprocess/expr/evaluate.ts
13698
- import { evaluateExpression as evaluateExpression2, formatExprValue, isTruthy as isTruthy2 } from "@wdprlib/ast";
13699
- function evaluateDirective(kind, match) {
13700
- if (kind === "expr") {
13701
- const result2 = evaluateExpression2(match.head);
13702
- if (result2.success)
13703
- return formatExprValue(result2.value);
13704
- if (result2.error === "empty expression")
13705
- return "";
13706
- return "ERROR";
13707
- }
13708
- if (kind === "if") {
13709
- if (!match.hasPipe)
13710
- return "";
13711
- return isTruthy2(match.head) ? match.thenText : match.elseText;
13712
- }
13713
- if (!match.hasPipe)
13714
- return "";
13715
- const result = evaluateExpression2(match.head);
13716
- if (!result.success)
13717
- return "ERROR";
13718
- return result.value !== 0 && !Number.isNaN(result.value) ? match.thenText : match.elseText;
13719
- }
13720
-
13721
13849
  // packages/parser/src/parser/preprocess/expr/chars.ts
13722
13850
  function isWhitespace(ch) {
13723
13851
  return ch === " " || ch === "\t" || ch === `
@@ -13746,6 +13874,30 @@ function matchDirectiveKind(source, i) {
13746
13874
  return null;
13747
13875
  }
13748
13876
 
13877
+ // packages/parser/src/parser/preprocess/expr/evaluate.ts
13878
+ import { evaluateExpression as evaluateExpression2, formatExprValue, isTruthy as isTruthy2 } from "@wdprlib/ast";
13879
+ function evaluateDirective(kind, match) {
13880
+ if (kind === "expr") {
13881
+ const result2 = evaluateExpression2(match.head);
13882
+ if (result2.success)
13883
+ return formatExprValue(result2.value);
13884
+ if (result2.error === "empty expression")
13885
+ return "";
13886
+ return "ERROR";
13887
+ }
13888
+ if (kind === "if") {
13889
+ if (!match.hasPipe)
13890
+ return "";
13891
+ return isTruthy2(match.head) ? match.thenText : match.elseText;
13892
+ }
13893
+ if (!match.hasPipe)
13894
+ return "";
13895
+ const result = evaluateExpression2(match.head);
13896
+ if (!result.success)
13897
+ return "ERROR";
13898
+ return result.value !== 0 && !Number.isNaN(result.value) ? match.thenText : match.elseText;
13899
+ }
13900
+
13749
13901
  // packages/parser/src/parser/preprocess/expr/parse.ts
13750
13902
  function tryParseInnermostDirective(source, start, kind) {
13751
13903
  const keywordLen = kind === "ifexpr" ? 6 : kind === "expr" ? 4 : 2;
@@ -13847,11 +13999,14 @@ function expandInnermost(source) {
13847
13999
  }
13848
14000
 
13849
14001
  // packages/parser/src/parser/preprocess/expr/index.ts
14002
+ var MAX_EXPR_NESTING = 64;
13850
14003
  function preprocessExpr(source) {
13851
14004
  if (!source.includes("[[#"))
13852
14005
  return source;
13853
14006
  const sentinels = makeUniqueSentinels(source);
13854
14007
  const { masked, placeholders } = maskRawRegions(source, sentinels);
14008
+ if (exceedsExprNestingLimit(masked))
14009
+ return source;
13855
14010
  const reduced = reduceExpr(masked);
13856
14011
  return restorePlaceholders(reduced, placeholders, sentinels);
13857
14012
  }
@@ -13866,6 +14021,26 @@ function reduceExpr(source) {
13866
14021
  }
13867
14022
  return current2;
13868
14023
  }
14024
+ function exceedsExprNestingLimit(source) {
14025
+ const expressionStack = [];
14026
+ let expressionDepth = 0;
14027
+ for (let i = 0;i < source.length; i++) {
14028
+ if (source.startsWith("[[", i)) {
14029
+ const isExpression = matchDirectiveKind(source, i) !== null;
14030
+ expressionStack.push(isExpression);
14031
+ if (isExpression && ++expressionDepth > MAX_EXPR_NESTING)
14032
+ return true;
14033
+ i++;
14034
+ continue;
14035
+ }
14036
+ if (source.startsWith("]]", i)) {
14037
+ if (expressionStack.pop())
14038
+ expressionDepth--;
14039
+ i++;
14040
+ }
14041
+ }
14042
+ return false;
14043
+ }
13869
14044
 
13870
14045
  // packages/parser/src/parser/parse/source.ts
13871
14046
  function prepareSourceForParse(source, options) {
@@ -13877,6 +14052,12 @@ function prepareSourceForParse(source, options) {
13877
14052
  // packages/parser/src/parser/parse/index.ts
13878
14053
  var COMPACT_TEXT_RUN_SOURCE_LENGTH = 1e5;
13879
14054
  function parse(source, options) {
14055
+ return parseSource(source, options);
14056
+ }
14057
+ function parseWithIncludeDeferral(source, options, deferInclude) {
14058
+ return parseSource(source, options, deferInclude);
14059
+ }
14060
+ function parseSource(source, options, deferInclude) {
13880
14061
  const plainResult = parsePlainNonAsciiDocument(source);
13881
14062
  if (plainResult) {
13882
14063
  return plainResult;
@@ -13890,10 +14071,12 @@ function parse(source, options) {
13890
14071
  trackPositions: options?.trackPositions,
13891
14072
  compactTextRuns: preprocessed.length >= COMPACT_TEXT_RUN_SOURCE_LENGTH
13892
14073
  });
13893
- return new Parser(tokens, options).parse();
14074
+ return deferInclude ? parseTokensWithIncludeDeferral(tokens, options ?? {}, deferInclude) : new Parser(tokens, options).parse();
13894
14075
  }
13895
14076
  // packages/parser/src/pipeline/process.ts
13896
- import { DEFAULT_SETTINGS as DEFAULT_SETTINGS2 } from "@wdprlib/ast";
14077
+ import {
14078
+ DEFAULT_SETTINGS as DEFAULT_SETTINGS2
14079
+ } from "@wdprlib/ast";
13897
14080
 
13898
14081
  // packages/parser/src/parser/rules/block/module/resolution/resolve-async.ts
13899
14082
  async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
@@ -14069,6 +14252,11 @@ async function resolveElementChildren(element, context, state) {
14069
14252
  }
14070
14253
 
14071
14254
  // packages/parser/src/pipeline/process.ts
14255
+ var DEFAULT_MODULE_MAX_PASSES = 5;
14256
+ var PIPELINE_DIAGNOSTIC_POSITION = {
14257
+ start: { line: 1, column: 1, offset: 0 },
14258
+ end: { line: 1, column: 1, offset: 0 }
14259
+ };
14072
14260
  async function processWikitext(source, options) {
14073
14261
  const settings = options.settings ?? DEFAULT_SETTINGS2;
14074
14262
  const callbackContext = {
@@ -14076,45 +14264,82 @@ async function processWikitext(source, options) {
14076
14264
  settings
14077
14265
  };
14078
14266
  const dependencies = [];
14267
+ const diagnostics = [];
14079
14268
  const fetchInclude = createRequestIncludeFetcher(options.dataProvider?.fetchInclude ? (pageRef) => options.dataProvider.fetchInclude(pageRef, callbackContext) : undefined);
14080
14269
  const resolveSource = async (input) => {
14081
- if (!fetchInclude)
14082
- return input;
14083
- const resolution = await resolveIncludesAsyncWithTrace(input, fetchInclude, {
14084
- maxIterations: options.includeMaxIterations,
14085
- settings
14086
- });
14087
- dependencies.push(...resolution.dependencies);
14088
- return resolution.source;
14270
+ let expanded = input;
14271
+ if (fetchInclude) {
14272
+ const resolution = await resolveIncludesAsyncWithTraceSelective(input, fetchInclude, (reference) => isCurrentPageInclude(reference.location, options.page), {
14273
+ maxIterations: options.includeMaxIterations,
14274
+ settings
14275
+ });
14276
+ dependencies.push(...resolution.dependencies);
14277
+ if (resolution.reachedMaxIterations) {
14278
+ diagnostics.push(createLimitDiagnostic("include-resolution-limit", `Include expansion stopped after ${options.includeMaxIterations ?? 10} iterations.`));
14279
+ }
14280
+ expanded = resolution.source;
14281
+ }
14282
+ return expanded;
14089
14283
  };
14090
- const expandedSource = await resolveSource(source);
14091
- const initial = parse(expandedSource, {
14092
- settings,
14093
- pageTags: options.page.tags,
14094
- appendImplicitFootnoteBlock: false
14095
- });
14096
- const extraction = extractDataRequirements(initial.ast);
14097
- const dataProvider = createModuleDataProvider(options, callbackContext);
14098
- const resolved = await resolveModulesWithAsyncParse(initial.ast, dataProvider, {
14099
- parse: async (fragmentSource) => parse(await resolveSource(fragmentSource), {
14284
+ const parseSource2 = async (input) => {
14285
+ const expanded = await resolveSource(input);
14286
+ return parseWithIncludeDeferral(expanded, {
14100
14287
  settings,
14101
14288
  pageTags: options.page.tags,
14102
14289
  appendImplicitFootnoteBlock: false
14103
- }),
14104
- compiledListPagesTemplates: extraction.compiledListPagesTemplates,
14105
- compiledListUsersTemplates: extraction.compiledListUsersTemplates,
14106
- requirements: extraction.requirements,
14107
- urlPath: options.page.urlPath,
14108
- pageTags: options.page.tags
14109
- });
14290
+ }, (location) => isCurrentPageInclude(location, options.page));
14291
+ };
14292
+ const initial = await parseSource2(source);
14293
+ diagnostics.push(...initial.diagnostics);
14294
+ const dataProvider = createModuleDataProvider(options, callbackContext);
14295
+ const parseFragment = parseSource2;
14296
+ let ast = initial.ast;
14297
+ for (let pass = 0;pass < DEFAULT_MODULE_MAX_PASSES; pass++) {
14298
+ const extraction = extractDataRequirements(ast);
14299
+ if (pass > 0 && !hasResolvableRequirements(extraction.requirements, options.dataProvider)) {
14300
+ break;
14301
+ }
14302
+ const resolved = await resolveModulesWithAsyncParse(ast, dataProvider, {
14303
+ parse: parseFragment,
14304
+ compiledListPagesTemplates: extraction.compiledListPagesTemplates,
14305
+ compiledListUsersTemplates: extraction.compiledListUsersTemplates,
14306
+ requirements: extraction.requirements,
14307
+ urlPath: options.page.urlPath,
14308
+ pageTags: options.page.tags
14309
+ });
14310
+ ast = resolved.ast;
14311
+ diagnostics.push(...resolved.diagnostics);
14312
+ }
14313
+ if (hasResolvableRequirements(extractDataRequirements(ast).requirements, options.dataProvider)) {
14314
+ diagnostics.push(createLimitDiagnostic("module-resolution-limit", `Module resolution stopped after ${DEFAULT_MODULE_MAX_PASSES} passes.`));
14315
+ }
14110
14316
  return {
14111
- ast: resolved.ast,
14317
+ ast,
14112
14318
  page: options.page,
14113
14319
  settings,
14114
- diagnostics: [...initial.diagnostics, ...resolved.diagnostics],
14320
+ diagnostics,
14115
14321
  dependencies
14116
14322
  };
14117
14323
  }
14324
+ function isCurrentPageInclude(location, page) {
14325
+ if (location.site !== null) {
14326
+ if (!page.site || location.site.toLowerCase() !== page.site.toLowerCase())
14327
+ return false;
14328
+ }
14329
+ const target = location.page.toLowerCase();
14330
+ return target === page.fullName.toLowerCase() || target === page.unixName?.toLowerCase();
14331
+ }
14332
+ function hasResolvableRequirements(requirements, provider) {
14333
+ return Boolean(provider?.fetchListPages && requirements.listPages.length > 0 || provider?.fetchListUsers && requirements.listUsers.length > 0 || provider?.fetchTagCloud && requirements.tagCloud.length > 0);
14334
+ }
14335
+ function createLimitDiagnostic(code, message) {
14336
+ return {
14337
+ severity: "warning",
14338
+ code,
14339
+ message,
14340
+ position: PIPELINE_DIAGNOSTIC_POSITION
14341
+ };
14342
+ }
14118
14343
  function createModuleDataProvider(options, context) {
14119
14344
  const provider = options.dataProvider;
14120
14345
  return {
@@ -14140,7 +14365,7 @@ function createRequestIncludeFetcher(fetcher) {
14140
14365
  }
14141
14366
  export {
14142
14367
  tokenize,
14143
- text,
14368
+ text2 as text,
14144
14369
  resolveTagCloud,
14145
14370
  resolveModules,
14146
14371
  resolveListUsers,
@@ -14157,13 +14382,14 @@ export {
14157
14382
  parseDateSelector,
14158
14383
  parseCategory,
14159
14384
  parse,
14160
- paragraph,
14385
+ paragraph2 as paragraph,
14161
14386
  normalizeQuery,
14387
+ matchesListPagesSelectors,
14162
14388
  listItemSubList,
14163
14389
  listItemElements,
14164
14390
  list,
14165
14391
  link,
14166
- lineBreak,
14392
+ lineBreak2 as lineBreak,
14167
14393
  italics,
14168
14394
  isTagCloudModule,
14169
14395
  isListUsersModule2 as isListUsersModule,
@@ -14172,6 +14398,7 @@ export {
14172
14398
  extractListUsersVariables,
14173
14399
  extractIncludeReferences,
14174
14400
  extractDataRequirements,
14401
+ definePageData,
14175
14402
  createToken,
14176
14403
  createSettings,
14177
14404
  createPosition,