@wdprlib/parser 2.0.10 → 2.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.cjs CHANGED
@@ -34,6 +34,7 @@ __export(exports_src, {
34
34
  text: () => import_ast5.text,
35
35
  resolveModules: () => resolveModules,
36
36
  resolveListUsers: () => resolveListUsers,
37
+ resolveIncludesAsync: () => resolveIncludesAsync,
37
38
  resolveIncludes: () => resolveIncludes,
38
39
  parseTags: () => parseTags,
39
40
  parseParent: () => parseParent,
@@ -9968,7 +9969,7 @@ function resolveIncludes(source, fetcher, options) {
9968
9969
  if (options?.settings && !options.settings.enablePageSyntax) {
9969
9970
  return source;
9970
9971
  }
9971
- const maxDepth = options?.maxDepth ?? 5;
9972
+ const maxIterations = options?.maxIterations ?? 10;
9972
9973
  const cache = new Map;
9973
9974
  const cachedFetcher = (pageRef) => {
9974
9975
  const key = normalizePageKey(pageRef);
@@ -9984,7 +9985,29 @@ function resolveIncludes(source, fetcher, options) {
9984
9985
  cache.set(key, result);
9985
9986
  return result;
9986
9987
  };
9987
- return expandText(source, cachedFetcher, 0, maxDepth, []);
9988
+ return expandIterative(source, cachedFetcher, maxIterations);
9989
+ }
9990
+ async function resolveIncludesAsync(source, fetcher, options) {
9991
+ if (options?.settings && !options.settings.enablePageSyntax) {
9992
+ return source;
9993
+ }
9994
+ const maxIterations = options?.maxIterations ?? 10;
9995
+ const cache = new Map;
9996
+ const cachedFetcher = async (pageRef) => {
9997
+ const key = normalizePageKey(pageRef);
9998
+ if (cache.has(key)) {
9999
+ return cache.get(key);
10000
+ }
10001
+ let result;
10002
+ try {
10003
+ result = await fetcher(pageRef);
10004
+ } catch {
10005
+ result = null;
10006
+ }
10007
+ cache.set(key, result);
10008
+ return result;
10009
+ };
10010
+ return expandIterativeAsync(source, cachedFetcher, maxIterations);
9988
10011
  }
9989
10012
  var INCLUDE_PATTERN = /^\[\[include\s([^\]]*(?:\](?!\])[^\]]*)*)\]\]/gim;
9990
10013
  function parseIncludeDirective(inner) {
@@ -10034,26 +10057,55 @@ function parseIncludeDirective(inner) {
10034
10057
  }
10035
10058
  return { location, variables };
10036
10059
  }
10037
- function expandText(source, fetcher, depth, maxDepth, trace) {
10038
- if (depth >= maxDepth)
10039
- return source;
10040
- return source.replace(INCLUDE_PATTERN, (_match, inner) => {
10041
- const { location, variables } = parseIncludeDirective(inner);
10042
- const pageKey = normalizePageKey(location);
10043
- if (trace.includes(pageKey)) {
10044
- return `[[div class="error-block"]]
10045
- Circular include detected: "${location.page}"
10060
+ function replaceOneInclude(_match, inner, fetcher) {
10061
+ const { location, variables } = parseIncludeDirective(inner);
10062
+ const content = fetcher(location);
10063
+ if (content === null) {
10064
+ return `[[div class="error-block"]]
10065
+ Page to be included "${location.page}" cannot be found!
10046
10066
  [[/div]]`;
10047
- }
10048
- const content = fetcher(location);
10049
- if (content === null) {
10050
- return `[[div class="error-block"]]
10067
+ }
10068
+ return substituteVariables(content, variables);
10069
+ }
10070
+ function expandIterative(source, fetcher, maxIterations) {
10071
+ let current = source;
10072
+ for (let i = 0;i < maxIterations; i++) {
10073
+ const previous = current;
10074
+ current = current.replace(INCLUDE_PATTERN, (_match, inner) => replaceOneInclude(_match, inner, fetcher));
10075
+ if (current === previous)
10076
+ break;
10077
+ }
10078
+ return current;
10079
+ }
10080
+ async function expandIterativeAsync(source, fetcher, maxIterations) {
10081
+ let current = source;
10082
+ for (let i = 0;i < maxIterations; i++) {
10083
+ const previous = current;
10084
+ const pattern = new RegExp(INCLUDE_PATTERN.source, INCLUDE_PATTERN.flags);
10085
+ let result = "";
10086
+ let lastPos = 0;
10087
+ let match;
10088
+ while ((match = pattern.exec(current)) !== null) {
10089
+ const fullMatch = match[0];
10090
+ const inner = match[1];
10091
+ result += current.slice(lastPos, match.index);
10092
+ const { location, variables } = parseIncludeDirective(inner);
10093
+ const content = await fetcher(location);
10094
+ if (content === null) {
10095
+ result += `[[div class="error-block"]]
10051
10096
  Page to be included "${location.page}" cannot be found!
10052
10097
  [[/div]]`;
10098
+ } else {
10099
+ result += substituteVariables(content, variables);
10100
+ }
10101
+ lastPos = match.index + fullMatch.length;
10053
10102
  }
10054
- const substituted = substituteVariables(content, variables);
10055
- return expandText(substituted, fetcher, depth + 1, maxDepth, [...trace, pageKey]);
10056
- });
10103
+ result += current.slice(lastPos);
10104
+ current = result;
10105
+ if (current === previous)
10106
+ break;
10107
+ }
10108
+ return current;
10057
10109
  }
10058
10110
  function normalizePageKey(location) {
10059
10111
  const site = location.site ?? "";
package/dist/index.d.cts CHANGED
@@ -859,21 +859,36 @@ import { PageRef, WikitextSettings as WikitextSettings3 } from "@wdprlib/ast";
859
859
  */
860
860
  type IncludeFetcher = (pageRef: PageRef) => string | null;
861
861
  /**
862
- * Options for resolveIncludes
862
+ * Async callback to fetch page content for include resolution.
863
+ * Returns a promise of the wikitext source, or null if the page does not exist.
864
+ *
865
+ * @security The fetcher is called with user-provided page references.
866
+ * Implementations should validate and sanitize page references before
867
+ * using them in database queries or file system access.
868
+ */
869
+ type AsyncIncludeFetcher = (pageRef: PageRef) => Promise<string | null>;
870
+ /**
871
+ * Options for resolveIncludes / resolveIncludesAsync
863
872
  */
864
873
  interface ResolveIncludesOptions {
865
- /** Maximum recursion depth for nested includes (default: 5) */
866
- maxDepth?: number;
874
+ /**
875
+ * Maximum number of expansion iterations (default: 10).
876
+ *
877
+ * Each iteration replaces all `[[include]]` directives in the current
878
+ * source with fetched content. Iteration stops when the source is
879
+ * unchanged or this limit is reached.
880
+ */
881
+ maxIterations?: number;
867
882
  /** Wikitext settings. If enablePageSyntax is false, includes are not expanded. */
868
883
  settings?: WikitextSettings3;
869
884
  }
870
885
  /**
871
886
  * Expand all [[include]] directives in the source text.
872
887
  *
873
- * Include directives are treated as macro expansions: `[[include page]]`
874
- * is replaced with the fetched page content (after variable substitution).
875
- * The result is a single expanded text that can be parsed as a whole,
876
- * allowing block structures (like div) to span across include boundaries.
888
+ * Uses Wikidot-compatible iterative expansion: each iteration replaces
889
+ * all include directives in the current source with fetched (and
890
+ * variable-substituted) content. Iteration continues until no further
891
+ * changes occur or `maxIterations` is reached.
877
892
  *
878
893
  * @example
879
894
  * ```ts
@@ -883,6 +898,21 @@ interface ResolveIncludesOptions {
883
898
  */
884
899
  declare function resolveIncludes(source: string, fetcher: IncludeFetcher, options?: ResolveIncludesOptions): string;
885
900
  /**
901
+ * Async version of {@link resolveIncludes}.
902
+ *
903
+ * Expand all [[include]] directives using an async fetcher, allowing
904
+ * page content to be loaded from async sources such as databases.
905
+ *
906
+ * @example
907
+ * ```ts
908
+ * const expanded = await resolveIncludesAsync(source, async (ref) => {
909
+ * return await db.getPageContent(ref.page);
910
+ * });
911
+ * const ast = parse(expanded);
912
+ * ```
913
+ */
914
+ declare function resolveIncludesAsync(source: string, fetcher: AsyncIncludeFetcher, options?: ResolveIncludesOptions): Promise<string>;
915
+ /**
886
916
  * Compile a ListUsers template string into an executable function.
887
917
  *
888
918
  * The template is split into alternating static strings and dynamic getter
@@ -981,4 +1011,4 @@ interface ResolveOptions {
981
1011
  */
982
1012
  declare function resolveModules(ast: SyntaxTree2, dataProvider: DataProvider, options: ResolveOptions): Promise<SyntaxTree2>;
983
1013
  import { STYLE_SLOT_PREFIX } from "@wdprlib/ast";
984
- export { tokenize, text, resolveModules, resolveListUsers, resolveIncludes, parseTags, parseParent, parseOrder, parseNumericSelector, parseDateSelector, parseCategory, parse, paragraph, normalizeQuery, listItemSubList, listItemElements, list, link, lineBreak, italics, isListUsersModule, horizontalRule, heading, extractListUsersVariables, extractDataRequirements, createToken, createSettings, createPosition, createPoint, container, compileTemplate, compileListUsersTemplate, bold, WikitextSettings4 as WikitextSettings, WikitextMode, Version2 as Version, VariableMap, VariableContext, UserInfo, TokenType, Token, TocEntry2 as TocEntry, TableRow, TableData, TableCell, TabData, SyntaxTree3 as SyntaxTree, SiteContext, STYLE_SLOT_PREFIX, ResolveOptions, ResolveIncludesOptions, Position2 as Position, Point, ParserOptions, Parser, ParseResult2 as ParseResult, ParseFunction, PageRef2 as PageRef, PageData, NormalizedTags, NormalizedParent, NormalizedOrder, NormalizedNumericSelector, NormalizedListPagesQuery, NormalizedDateSelector, NormalizedCategory, Module4 as Module, ListUsersVariableContext, ListUsersVariable, ListUsersUserData, ListUsersExternalData, ListUsersDataRequirement, ListUsersDataFetcher, ListUsersCompiledTemplate, ListType, ListPagesVariable, ListPagesQuery, ListPagesExternalData, ListPagesDataRequirement, ListPagesDataFetcher, ListItem, ListData, LinkType, LinkLocation, LinkLabel, LexerOptions, Lexer, IncludeFetcher, ImageSource, HeadingLevel, Heading, HeaderType, FloatAlignment, ExtractionResult, Embed, Element6 as Element, DiagnosticSeverity, Diagnostic2 as Diagnostic, DefinitionListItem, DateItem, DataRequirements, DataProvider, DEFAULT_SETTINGS, ContainerType, ContainerData, CompiledTemplate, CollapsibleData, CodeBlockData2 as CodeBlockData, ClearFloat, AttributeMap, AnchorTarget, Alignment, AlignType };
1014
+ export { tokenize, text, resolveModules, resolveListUsers, resolveIncludesAsync, resolveIncludes, parseTags, parseParent, parseOrder, parseNumericSelector, parseDateSelector, parseCategory, parse, paragraph, normalizeQuery, listItemSubList, listItemElements, list, link, lineBreak, italics, isListUsersModule, horizontalRule, heading, extractListUsersVariables, extractDataRequirements, createToken, createSettings, createPosition, createPoint, container, compileTemplate, compileListUsersTemplate, bold, WikitextSettings4 as WikitextSettings, WikitextMode, Version2 as Version, VariableMap, VariableContext, UserInfo, TokenType, Token, TocEntry2 as TocEntry, TableRow, TableData, TableCell, TabData, SyntaxTree3 as SyntaxTree, SiteContext, STYLE_SLOT_PREFIX, ResolveOptions, ResolveIncludesOptions, Position2 as Position, Point, ParserOptions, Parser, ParseResult2 as ParseResult, ParseFunction, PageRef2 as PageRef, PageData, NormalizedTags, NormalizedParent, NormalizedOrder, NormalizedNumericSelector, NormalizedListPagesQuery, NormalizedDateSelector, NormalizedCategory, Module4 as Module, ListUsersVariableContext, ListUsersVariable, ListUsersUserData, ListUsersExternalData, ListUsersDataRequirement, ListUsersDataFetcher, ListUsersCompiledTemplate, ListType, ListPagesVariable, ListPagesQuery, ListPagesExternalData, ListPagesDataRequirement, ListPagesDataFetcher, ListItem, ListData, LinkType, LinkLocation, LinkLabel, LexerOptions, Lexer, IncludeFetcher, ImageSource, HeadingLevel, Heading, HeaderType, FloatAlignment, ExtractionResult, Embed, Element6 as Element, DiagnosticSeverity, Diagnostic2 as Diagnostic, DefinitionListItem, DateItem, DataRequirements, DataProvider, DEFAULT_SETTINGS, ContainerType, ContainerData, CompiledTemplate, CollapsibleData, CodeBlockData2 as CodeBlockData, ClearFloat, AttributeMap, AsyncIncludeFetcher, AnchorTarget, Alignment, AlignType };
package/dist/index.d.ts CHANGED
@@ -859,21 +859,36 @@ import { PageRef, WikitextSettings as WikitextSettings3 } from "@wdprlib/ast";
859
859
  */
860
860
  type IncludeFetcher = (pageRef: PageRef) => string | null;
861
861
  /**
862
- * Options for resolveIncludes
862
+ * Async callback to fetch page content for include resolution.
863
+ * Returns a promise of the wikitext source, or null if the page does not exist.
864
+ *
865
+ * @security The fetcher is called with user-provided page references.
866
+ * Implementations should validate and sanitize page references before
867
+ * using them in database queries or file system access.
868
+ */
869
+ type AsyncIncludeFetcher = (pageRef: PageRef) => Promise<string | null>;
870
+ /**
871
+ * Options for resolveIncludes / resolveIncludesAsync
863
872
  */
864
873
  interface ResolveIncludesOptions {
865
- /** Maximum recursion depth for nested includes (default: 5) */
866
- maxDepth?: number;
874
+ /**
875
+ * Maximum number of expansion iterations (default: 10).
876
+ *
877
+ * Each iteration replaces all `[[include]]` directives in the current
878
+ * source with fetched content. Iteration stops when the source is
879
+ * unchanged or this limit is reached.
880
+ */
881
+ maxIterations?: number;
867
882
  /** Wikitext settings. If enablePageSyntax is false, includes are not expanded. */
868
883
  settings?: WikitextSettings3;
869
884
  }
870
885
  /**
871
886
  * Expand all [[include]] directives in the source text.
872
887
  *
873
- * Include directives are treated as macro expansions: `[[include page]]`
874
- * is replaced with the fetched page content (after variable substitution).
875
- * The result is a single expanded text that can be parsed as a whole,
876
- * allowing block structures (like div) to span across include boundaries.
888
+ * Uses Wikidot-compatible iterative expansion: each iteration replaces
889
+ * all include directives in the current source with fetched (and
890
+ * variable-substituted) content. Iteration continues until no further
891
+ * changes occur or `maxIterations` is reached.
877
892
  *
878
893
  * @example
879
894
  * ```ts
@@ -883,6 +898,21 @@ interface ResolveIncludesOptions {
883
898
  */
884
899
  declare function resolveIncludes(source: string, fetcher: IncludeFetcher, options?: ResolveIncludesOptions): string;
885
900
  /**
901
+ * Async version of {@link resolveIncludes}.
902
+ *
903
+ * Expand all [[include]] directives using an async fetcher, allowing
904
+ * page content to be loaded from async sources such as databases.
905
+ *
906
+ * @example
907
+ * ```ts
908
+ * const expanded = await resolveIncludesAsync(source, async (ref) => {
909
+ * return await db.getPageContent(ref.page);
910
+ * });
911
+ * const ast = parse(expanded);
912
+ * ```
913
+ */
914
+ declare function resolveIncludesAsync(source: string, fetcher: AsyncIncludeFetcher, options?: ResolveIncludesOptions): Promise<string>;
915
+ /**
886
916
  * Compile a ListUsers template string into an executable function.
887
917
  *
888
918
  * The template is split into alternating static strings and dynamic getter
@@ -981,4 +1011,4 @@ interface ResolveOptions {
981
1011
  */
982
1012
  declare function resolveModules(ast: SyntaxTree2, dataProvider: DataProvider, options: ResolveOptions): Promise<SyntaxTree2>;
983
1013
  import { STYLE_SLOT_PREFIX } from "@wdprlib/ast";
984
- export { tokenize, text, resolveModules, resolveListUsers, resolveIncludes, parseTags, parseParent, parseOrder, parseNumericSelector, parseDateSelector, parseCategory, parse, paragraph, normalizeQuery, listItemSubList, listItemElements, list, link, lineBreak, italics, isListUsersModule, horizontalRule, heading, extractListUsersVariables, extractDataRequirements, createToken, createSettings, createPosition, createPoint, container, compileTemplate, compileListUsersTemplate, bold, WikitextSettings4 as WikitextSettings, WikitextMode, Version2 as Version, VariableMap, VariableContext, UserInfo, TokenType, Token, TocEntry2 as TocEntry, TableRow, TableData, TableCell, TabData, SyntaxTree3 as SyntaxTree, SiteContext, STYLE_SLOT_PREFIX, ResolveOptions, ResolveIncludesOptions, Position2 as Position, Point, ParserOptions, Parser, ParseResult2 as ParseResult, ParseFunction, PageRef2 as PageRef, PageData, NormalizedTags, NormalizedParent, NormalizedOrder, NormalizedNumericSelector, NormalizedListPagesQuery, NormalizedDateSelector, NormalizedCategory, Module4 as Module, ListUsersVariableContext, ListUsersVariable, ListUsersUserData, ListUsersExternalData, ListUsersDataRequirement, ListUsersDataFetcher, ListUsersCompiledTemplate, ListType, ListPagesVariable, ListPagesQuery, ListPagesExternalData, ListPagesDataRequirement, ListPagesDataFetcher, ListItem, ListData, LinkType, LinkLocation, LinkLabel, LexerOptions, Lexer, IncludeFetcher, ImageSource, HeadingLevel, Heading, HeaderType, FloatAlignment, ExtractionResult, Embed, Element6 as Element, DiagnosticSeverity, Diagnostic2 as Diagnostic, DefinitionListItem, DateItem, DataRequirements, DataProvider, DEFAULT_SETTINGS, ContainerType, ContainerData, CompiledTemplate, CollapsibleData, CodeBlockData2 as CodeBlockData, ClearFloat, AttributeMap, AnchorTarget, Alignment, AlignType };
1014
+ export { tokenize, text, resolveModules, resolveListUsers, resolveIncludesAsync, resolveIncludes, parseTags, parseParent, parseOrder, parseNumericSelector, parseDateSelector, parseCategory, parse, paragraph, normalizeQuery, listItemSubList, listItemElements, list, link, lineBreak, italics, isListUsersModule, horizontalRule, heading, extractListUsersVariables, extractDataRequirements, createToken, createSettings, createPosition, createPoint, container, compileTemplate, compileListUsersTemplate, bold, WikitextSettings4 as WikitextSettings, WikitextMode, Version2 as Version, VariableMap, VariableContext, UserInfo, TokenType, Token, TocEntry2 as TocEntry, TableRow, TableData, TableCell, TabData, SyntaxTree3 as SyntaxTree, SiteContext, STYLE_SLOT_PREFIX, ResolveOptions, ResolveIncludesOptions, Position2 as Position, Point, ParserOptions, Parser, ParseResult2 as ParseResult, ParseFunction, PageRef2 as PageRef, PageData, NormalizedTags, NormalizedParent, NormalizedOrder, NormalizedNumericSelector, NormalizedListPagesQuery, NormalizedDateSelector, NormalizedCategory, Module4 as Module, ListUsersVariableContext, ListUsersVariable, ListUsersUserData, ListUsersExternalData, ListUsersDataRequirement, ListUsersDataFetcher, ListUsersCompiledTemplate, ListType, ListPagesVariable, ListPagesQuery, ListPagesExternalData, ListPagesDataRequirement, ListPagesDataFetcher, ListItem, ListData, LinkType, LinkLocation, LinkLabel, LexerOptions, Lexer, IncludeFetcher, ImageSource, HeadingLevel, Heading, HeaderType, FloatAlignment, ExtractionResult, Embed, Element6 as Element, DiagnosticSeverity, Diagnostic2 as Diagnostic, DefinitionListItem, DateItem, DataRequirements, DataProvider, DEFAULT_SETTINGS, ContainerType, ContainerData, CompiledTemplate, CollapsibleData, CodeBlockData2 as CodeBlockData, ClearFloat, AttributeMap, AsyncIncludeFetcher, AnchorTarget, Alignment, AlignType };
package/dist/index.js CHANGED
@@ -9913,7 +9913,7 @@ function resolveIncludes(source, fetcher, options) {
9913
9913
  if (options?.settings && !options.settings.enablePageSyntax) {
9914
9914
  return source;
9915
9915
  }
9916
- const maxDepth = options?.maxDepth ?? 5;
9916
+ const maxIterations = options?.maxIterations ?? 10;
9917
9917
  const cache = new Map;
9918
9918
  const cachedFetcher = (pageRef) => {
9919
9919
  const key = normalizePageKey(pageRef);
@@ -9929,7 +9929,29 @@ function resolveIncludes(source, fetcher, options) {
9929
9929
  cache.set(key, result);
9930
9930
  return result;
9931
9931
  };
9932
- return expandText(source, cachedFetcher, 0, maxDepth, []);
9932
+ return expandIterative(source, cachedFetcher, maxIterations);
9933
+ }
9934
+ async function resolveIncludesAsync(source, fetcher, options) {
9935
+ if (options?.settings && !options.settings.enablePageSyntax) {
9936
+ return source;
9937
+ }
9938
+ const maxIterations = options?.maxIterations ?? 10;
9939
+ const cache = new Map;
9940
+ const cachedFetcher = async (pageRef) => {
9941
+ const key = normalizePageKey(pageRef);
9942
+ if (cache.has(key)) {
9943
+ return cache.get(key);
9944
+ }
9945
+ let result;
9946
+ try {
9947
+ result = await fetcher(pageRef);
9948
+ } catch {
9949
+ result = null;
9950
+ }
9951
+ cache.set(key, result);
9952
+ return result;
9953
+ };
9954
+ return expandIterativeAsync(source, cachedFetcher, maxIterations);
9933
9955
  }
9934
9956
  var INCLUDE_PATTERN = /^\[\[include\s([^\]]*(?:\](?!\])[^\]]*)*)\]\]/gim;
9935
9957
  function parseIncludeDirective(inner) {
@@ -9979,26 +10001,55 @@ function parseIncludeDirective(inner) {
9979
10001
  }
9980
10002
  return { location, variables };
9981
10003
  }
9982
- function expandText(source, fetcher, depth, maxDepth, trace) {
9983
- if (depth >= maxDepth)
9984
- return source;
9985
- return source.replace(INCLUDE_PATTERN, (_match, inner) => {
9986
- const { location, variables } = parseIncludeDirective(inner);
9987
- const pageKey = normalizePageKey(location);
9988
- if (trace.includes(pageKey)) {
9989
- return `[[div class="error-block"]]
9990
- Circular include detected: "${location.page}"
10004
+ function replaceOneInclude(_match, inner, fetcher) {
10005
+ const { location, variables } = parseIncludeDirective(inner);
10006
+ const content = fetcher(location);
10007
+ if (content === null) {
10008
+ return `[[div class="error-block"]]
10009
+ Page to be included "${location.page}" cannot be found!
9991
10010
  [[/div]]`;
9992
- }
9993
- const content = fetcher(location);
9994
- if (content === null) {
9995
- return `[[div class="error-block"]]
10011
+ }
10012
+ return substituteVariables(content, variables);
10013
+ }
10014
+ function expandIterative(source, fetcher, maxIterations) {
10015
+ let current = source;
10016
+ for (let i = 0;i < maxIterations; i++) {
10017
+ const previous = current;
10018
+ current = current.replace(INCLUDE_PATTERN, (_match, inner) => replaceOneInclude(_match, inner, fetcher));
10019
+ if (current === previous)
10020
+ break;
10021
+ }
10022
+ return current;
10023
+ }
10024
+ async function expandIterativeAsync(source, fetcher, maxIterations) {
10025
+ let current = source;
10026
+ for (let i = 0;i < maxIterations; i++) {
10027
+ const previous = current;
10028
+ const pattern = new RegExp(INCLUDE_PATTERN.source, INCLUDE_PATTERN.flags);
10029
+ let result = "";
10030
+ let lastPos = 0;
10031
+ let match;
10032
+ while ((match = pattern.exec(current)) !== null) {
10033
+ const fullMatch = match[0];
10034
+ const inner = match[1];
10035
+ result += current.slice(lastPos, match.index);
10036
+ const { location, variables } = parseIncludeDirective(inner);
10037
+ const content = await fetcher(location);
10038
+ if (content === null) {
10039
+ result += `[[div class="error-block"]]
9996
10040
  Page to be included "${location.page}" cannot be found!
9997
10041
  [[/div]]`;
10042
+ } else {
10043
+ result += substituteVariables(content, variables);
10044
+ }
10045
+ lastPos = match.index + fullMatch.length;
9998
10046
  }
9999
- const substituted = substituteVariables(content, variables);
10000
- return expandText(substituted, fetcher, depth + 1, maxDepth, [...trace, pageKey]);
10001
- });
10047
+ result += current.slice(lastPos);
10048
+ current = result;
10049
+ if (current === previous)
10050
+ break;
10051
+ }
10052
+ return current;
10002
10053
  }
10003
10054
  function normalizePageKey(location) {
10004
10055
  const site = location.site ?? "";
@@ -10227,6 +10278,7 @@ export {
10227
10278
  text,
10228
10279
  resolveModules,
10229
10280
  resolveListUsers,
10281
+ resolveIncludesAsync,
10230
10282
  resolveIncludes,
10231
10283
  parseTags,
10232
10284
  parseParent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdprlib/parser",
3
- "version": "2.0.10",
3
+ "version": "2.1.0",
4
4
  "description": "Parser for Wikidot markup",
5
5
  "keywords": [
6
6
  "ast",