@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 +70 -18
- package/dist/index.d.cts +38 -8
- package/dist/index.d.ts +38 -8
- package/dist/index.js +70 -18
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
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
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
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
|
-
|
|
10055
|
-
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
866
|
-
|
|
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
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
*
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
866
|
-
|
|
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
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
*
|
|
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
|
|
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
|
|
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
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
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
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
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
|
-
|
|
10000
|
-
|
|
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,
|