@wdprlib/parser 0.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 +8556 -0
- package/dist/index.d.cts +743 -0
- package/dist/index.d.ts +743 -0
- package/dist/index.js +8540 -0
- package/package.json +44 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
import { Position as Position2, Point, Version as Version2, Element as Element6, SyntaxTree as SyntaxTree4, ContainerType, ContainerData, AttributeMap, VariableMap, Alignment, LinkType, LinkLocation, LinkLabel, PageRef as PageRef2, ImageSource, FloatAlignment, ListType, ListItem, ListData, CodeBlockData as CodeBlockData2, TabData, TableCell, TableRow, TableData, DefinitionListItem, Module as Module4, CollapsibleData, ClearFloat, AnchorTarget, HeaderType, AlignType, HeadingLevel, Heading, DateItem, Embed, TocEntry as TocEntry2 } from "@wdprlib/ast";
|
|
2
|
+
import { createPoint, createPosition, text, container, paragraph, bold, italics, heading, lineBreak, horizontalRule, link, list, listItemElements, listItemSubList } from "@wdprlib/ast";
|
|
3
|
+
import { Position } from "@wdprlib/ast";
|
|
4
|
+
/**
|
|
5
|
+
* Token types for Wikidot markup
|
|
6
|
+
*/
|
|
7
|
+
type TokenType = "EOF" | "TEXT" | "IDENTIFIER" | "NEWLINE" | "WHITESPACE" | "BLOCK_OPEN" | "BLOCK_CLOSE" | "BLOCK_END_OPEN" | "BOLD_MARKER" | "ITALIC_MARKER" | "UNDERLINE_MARKER" | "STRIKE_MARKER" | "SUPER_MARKER" | "SUB_MARKER" | "MONO_MARKER" | "MONO_CLOSE" | "HEADING_MARKER" | "HR_MARKER" | "LIST_BULLET" | "LIST_NUMBER" | "BLOCKQUOTE_MARKER" | "TABLE_MARKER" | "TABLE_HEADER" | "TABLE_LEFT" | "TABLE_CENTER" | "TABLE_RIGHT" | "CODE_OPEN" | "CODE_CLOSE" | "LINK_OPEN" | "LINK_CLOSE" | "BRACKET_OPEN" | "BRACKET_CLOSE" | "BRACKET_ANCHOR" | "BRACKET_STAR" | "PIPE" | "EQUALS" | "COLON" | "SLASH" | "STAR" | "HASH" | "AT" | "AMPERSAND" | "BACKSLASH" | "QUOTED_STRING" | "RAW_OPEN" | "RAW_CLOSE" | "RAW_BLOCK_OPEN" | "RAW_BLOCK_CLOSE" | "COLOR_MARKER" | "UNDERSCORE" | "COMMENT_OPEN" | "COMMENT_CLOSE" | "CLEAR_FLOAT" | "CLEAR_FLOAT_LEFT" | "CLEAR_FLOAT_RIGHT" | "LEFT_DOUBLE_ANGLE" | "RIGHT_DOUBLE_ANGLE";
|
|
8
|
+
/**
|
|
9
|
+
* Token
|
|
10
|
+
*/
|
|
11
|
+
interface Token {
|
|
12
|
+
type: TokenType;
|
|
13
|
+
value: string;
|
|
14
|
+
position: Position;
|
|
15
|
+
/** Whether this token appears at the start of a line */
|
|
16
|
+
lineStart: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a token
|
|
20
|
+
*/
|
|
21
|
+
declare function createToken(type: TokenType, value: string, position: Position, lineStart?: boolean): Token;
|
|
22
|
+
/**
|
|
23
|
+
* Lexer options
|
|
24
|
+
*/
|
|
25
|
+
interface LexerOptions {
|
|
26
|
+
/** Track position information */
|
|
27
|
+
trackPositions?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Wikidot markup lexer
|
|
31
|
+
*/
|
|
32
|
+
declare class Lexer {
|
|
33
|
+
private state;
|
|
34
|
+
private options;
|
|
35
|
+
constructor(source: string, options?: LexerOptions);
|
|
36
|
+
/**
|
|
37
|
+
* Tokenize the entire source
|
|
38
|
+
*/
|
|
39
|
+
tokenize(): Token[];
|
|
40
|
+
/**
|
|
41
|
+
* Check if at end of source
|
|
42
|
+
*/
|
|
43
|
+
private isAtEnd;
|
|
44
|
+
/**
|
|
45
|
+
* Get current character
|
|
46
|
+
*/
|
|
47
|
+
private current;
|
|
48
|
+
/**
|
|
49
|
+
* Check if source matches pattern at current position
|
|
50
|
+
*/
|
|
51
|
+
private match;
|
|
52
|
+
/**
|
|
53
|
+
* Advance position by n characters
|
|
54
|
+
*/
|
|
55
|
+
private advance;
|
|
56
|
+
/**
|
|
57
|
+
* Add token
|
|
58
|
+
*/
|
|
59
|
+
private addToken;
|
|
60
|
+
/**
|
|
61
|
+
* Scan a single token
|
|
62
|
+
*/
|
|
63
|
+
private scanToken;
|
|
64
|
+
/**
|
|
65
|
+
* Check if character is alphanumeric (for identifier tokens)
|
|
66
|
+
*/
|
|
67
|
+
private isAlphanumeric;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Tokenize source string
|
|
71
|
+
*/
|
|
72
|
+
declare function tokenize(source: string, options?: LexerOptions): Token[];
|
|
73
|
+
import { SyntaxTree } from "@wdprlib/ast";
|
|
74
|
+
/**
|
|
75
|
+
* Parser options
|
|
76
|
+
*/
|
|
77
|
+
interface ParserOptions {
|
|
78
|
+
/** Wikidot version */
|
|
79
|
+
version?: "wikidot";
|
|
80
|
+
/** Track position information */
|
|
81
|
+
trackPositions?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wikidot markup parser
|
|
85
|
+
*/
|
|
86
|
+
declare class Parser {
|
|
87
|
+
private ctx;
|
|
88
|
+
constructor(tokens: Token[], options?: ParserOptions);
|
|
89
|
+
/**
|
|
90
|
+
* Parse tokens into SyntaxTree
|
|
91
|
+
*/
|
|
92
|
+
parse(): SyntaxTree;
|
|
93
|
+
/**
|
|
94
|
+
* Check if at end of tokens
|
|
95
|
+
*/
|
|
96
|
+
private isAtEnd;
|
|
97
|
+
/**
|
|
98
|
+
* Get current token
|
|
99
|
+
*/
|
|
100
|
+
private currentToken;
|
|
101
|
+
/**
|
|
102
|
+
* Create EOF token
|
|
103
|
+
*/
|
|
104
|
+
private eofToken;
|
|
105
|
+
/**
|
|
106
|
+
* Skip whitespace tokens
|
|
107
|
+
*/
|
|
108
|
+
private skipWhitespace;
|
|
109
|
+
/**
|
|
110
|
+
* Parse block element(s)
|
|
111
|
+
* Returns an array because some rules (like list) may return multiple elements
|
|
112
|
+
*/
|
|
113
|
+
private parseBlock;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Parse source string into SyntaxTree
|
|
117
|
+
*/
|
|
118
|
+
declare function parse(source: string, options?: ParserOptions): SyntaxTree;
|
|
119
|
+
import { Element as Element2 } from "@wdprlib/ast";
|
|
120
|
+
/**
|
|
121
|
+
* Parser function type for re-parsing substituted templates
|
|
122
|
+
* Used by ListPages and ListUsers modules
|
|
123
|
+
*/
|
|
124
|
+
type ParseFunction = (input: string) => {
|
|
125
|
+
elements: Element2[];
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* ListUsers module types
|
|
129
|
+
*/
|
|
130
|
+
/**
|
|
131
|
+
* Supported template variables
|
|
132
|
+
*/
|
|
133
|
+
type ListUsersVariable = "number" | "title" | "name";
|
|
134
|
+
/**
|
|
135
|
+
* User data provided by external source
|
|
136
|
+
*/
|
|
137
|
+
interface ListUsersUserData {
|
|
138
|
+
number: number;
|
|
139
|
+
title: string;
|
|
140
|
+
name: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Data requirement for a single ListUsers module
|
|
144
|
+
*/
|
|
145
|
+
interface ListUsersDataRequirement {
|
|
146
|
+
id: number;
|
|
147
|
+
users: string;
|
|
148
|
+
neededVariables: ListUsersVariable[];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* External data for a single ListUsers module
|
|
152
|
+
* Note: ListUsers returns only the logged-in user
|
|
153
|
+
*/
|
|
154
|
+
interface ListUsersExternalData {
|
|
155
|
+
user: ListUsersUserData;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Callback to fetch data for a ListUsers module
|
|
159
|
+
*/
|
|
160
|
+
type ListUsersDataFetcher = (requirement: ListUsersDataRequirement) => ListUsersExternalData | null | undefined | Promise<ListUsersExternalData | null | undefined>;
|
|
161
|
+
/**
|
|
162
|
+
* Context passed to compiled template
|
|
163
|
+
*/
|
|
164
|
+
interface ListUsersVariableContext {
|
|
165
|
+
user: ListUsersUserData;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Compiled template function
|
|
169
|
+
*/
|
|
170
|
+
type ListUsersCompiledTemplate = (ctx: ListUsersVariableContext) => string;
|
|
171
|
+
/**
|
|
172
|
+
* ListPages module types
|
|
173
|
+
*/
|
|
174
|
+
/**
|
|
175
|
+
* ListPages query parameters for page selection
|
|
176
|
+
*
|
|
177
|
+
* @security All string fields contain **untrusted user input** from wikitext.
|
|
178
|
+
* When using these values in database queries:
|
|
179
|
+
* - **NEVER** interpolate directly into SQL/NoSQL query strings
|
|
180
|
+
* - **ALWAYS** use parameterized queries or prepared statements
|
|
181
|
+
* - For ORDER BY clauses, use a whitelist of allowed column names
|
|
182
|
+
*
|
|
183
|
+
* @example Safe usage with SQL
|
|
184
|
+
* ```typescript
|
|
185
|
+
* // GOOD: Parameterized query
|
|
186
|
+
* db.query("SELECT * FROM pages WHERE category = ?", [query.category]);
|
|
187
|
+
*
|
|
188
|
+
* // BAD: String interpolation (SQL injection vulnerable!)
|
|
189
|
+
* db.query(`SELECT * FROM pages WHERE category = '${query.category}'`);
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
interface ListPagesQuery {
|
|
193
|
+
/** Page type selector */
|
|
194
|
+
pagetype?: "normal" | "hidden" | "*";
|
|
195
|
+
/**
|
|
196
|
+
* Category selector
|
|
197
|
+
* @untrusted User input - use parameterized queries
|
|
198
|
+
*/
|
|
199
|
+
category?: string;
|
|
200
|
+
/**
|
|
201
|
+
* Tag selector (e.g., "+fruit -admin")
|
|
202
|
+
* @untrusted User input - use parameterized queries
|
|
203
|
+
*/
|
|
204
|
+
tags?: string;
|
|
205
|
+
/**
|
|
206
|
+
* Parent page selector
|
|
207
|
+
* @untrusted User input - use parameterized queries
|
|
208
|
+
*/
|
|
209
|
+
parent?: string;
|
|
210
|
+
/**
|
|
211
|
+
* Link target selector
|
|
212
|
+
* @untrusted User input - use parameterized queries
|
|
213
|
+
*/
|
|
214
|
+
linkTo?: string;
|
|
215
|
+
/**
|
|
216
|
+
* Created date selector
|
|
217
|
+
* @untrusted User input - use parameterized queries
|
|
218
|
+
*/
|
|
219
|
+
createdAt?: string;
|
|
220
|
+
/**
|
|
221
|
+
* Updated date selector
|
|
222
|
+
* @untrusted User input - use parameterized queries
|
|
223
|
+
*/
|
|
224
|
+
updatedAt?: string;
|
|
225
|
+
/**
|
|
226
|
+
* Author selector
|
|
227
|
+
* @untrusted User input - use parameterized queries
|
|
228
|
+
*/
|
|
229
|
+
createdBy?: string;
|
|
230
|
+
/**
|
|
231
|
+
* Rating selector
|
|
232
|
+
* @untrusted User input - use parameterized queries
|
|
233
|
+
*/
|
|
234
|
+
rating?: string;
|
|
235
|
+
/**
|
|
236
|
+
* Votes selector
|
|
237
|
+
* @untrusted User input - use parameterized queries
|
|
238
|
+
*/
|
|
239
|
+
votes?: string;
|
|
240
|
+
/**
|
|
241
|
+
* Page name selector
|
|
242
|
+
* @untrusted User input - use parameterized queries
|
|
243
|
+
*/
|
|
244
|
+
name?: string;
|
|
245
|
+
/**
|
|
246
|
+
* Full page name selector (category:name)
|
|
247
|
+
* @untrusted User input - use parameterized queries
|
|
248
|
+
*/
|
|
249
|
+
fullname?: string;
|
|
250
|
+
/** Range selector relative to current page */
|
|
251
|
+
range?: "." | "before" | "after" | "others";
|
|
252
|
+
/**
|
|
253
|
+
* Data form field selectors
|
|
254
|
+
* @untrusted Both keys and values are user input
|
|
255
|
+
*/
|
|
256
|
+
dataFormFields?: Record<string, string>;
|
|
257
|
+
/**
|
|
258
|
+
* Ordering specification
|
|
259
|
+
* @untrusted User input - use whitelist validation for ORDER BY
|
|
260
|
+
*/
|
|
261
|
+
order?: string;
|
|
262
|
+
/** Pagination offset */
|
|
263
|
+
offset?: number;
|
|
264
|
+
/** Maximum number of results */
|
|
265
|
+
limit?: number;
|
|
266
|
+
/** Results per page */
|
|
267
|
+
perPage?: number;
|
|
268
|
+
/** Reverse order */
|
|
269
|
+
reverse?: boolean;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* All supported ListPages template variables
|
|
273
|
+
*/
|
|
274
|
+
type ListPagesVariable = "created_at" | "created_by" | "created_by_unix" | "created_by_id" | "created_by_linked" | "updated_at" | "updated_by" | "updated_by_unix" | "updated_by_id" | "updated_by_linked" | "commented_at" | "commented_by" | "commented_by_unix" | "commented_by_id" | "commented_by_linked" | "name" | "category" | "fullname" | "title" | "title_linked" | "link" | "parent_name" | "parent_category" | "parent_fullname" | "parent_title" | "parent_title_linked" | "content" | "content_n" | "preview" | "preview_n" | "summary" | "first_paragraph" | "tags" | "tags_linked" | "_tags" | "_tags_linked" | "form_data" | "form_raw" | "form_label" | "form_hint" | "children" | "comments" | "size" | "rating" | "rating_votes" | "rating_percent" | "revisions" | "index" | "total" | "limit" | "total_or_limit" | "site_title" | "site_name" | "site_domain";
|
|
275
|
+
/**
|
|
276
|
+
* Data requirement for a single ListPages module
|
|
277
|
+
*/
|
|
278
|
+
interface ListPagesDataRequirement {
|
|
279
|
+
/** Unique identifier for this module instance */
|
|
280
|
+
id: number;
|
|
281
|
+
/** Query parameters */
|
|
282
|
+
query: ListPagesQuery;
|
|
283
|
+
/** Variables used in the template */
|
|
284
|
+
neededVariables: ListPagesVariable[];
|
|
285
|
+
/** Indices needed for content{n} */
|
|
286
|
+
contentSectionIndices?: number[];
|
|
287
|
+
/** Lengths needed for preview(n) */
|
|
288
|
+
previewLengths?: number[];
|
|
289
|
+
/** Field names needed for form_data{field} etc */
|
|
290
|
+
formFields?: string[];
|
|
291
|
+
/** Prefix for tags_linked|prefix */
|
|
292
|
+
tagsLinkPrefix?: string;
|
|
293
|
+
/** Prefix for _tags_linked|prefix */
|
|
294
|
+
hiddenTagsLinkPrefix?: string;
|
|
295
|
+
/**
|
|
296
|
+
* URL attribute prefix for multiple ListPages modules
|
|
297
|
+
* When set, URL parameters are prefixed (e.g., "page2" -> "/page2_limit/1")
|
|
298
|
+
*/
|
|
299
|
+
urlAttrPrefix?: string;
|
|
300
|
+
/**
|
|
301
|
+
* Raw attribute values before URL resolution
|
|
302
|
+
* Contains original string values that may include "@URL" or "@URL|default" format
|
|
303
|
+
* External applications should use these to resolve URL parameters
|
|
304
|
+
*/
|
|
305
|
+
rawAttributes: Record<string, string>;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* All data requirements from parsing
|
|
309
|
+
*/
|
|
310
|
+
interface DataRequirements {
|
|
311
|
+
listPages: ListPagesDataRequirement[];
|
|
312
|
+
listUsers: ListUsersDataRequirement[];
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* User information
|
|
316
|
+
*/
|
|
317
|
+
interface UserInfo {
|
|
318
|
+
id: number;
|
|
319
|
+
name: string;
|
|
320
|
+
unixName: string;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Page data provided by external source
|
|
324
|
+
*/
|
|
325
|
+
interface PageData {
|
|
326
|
+
name: string;
|
|
327
|
+
category: string;
|
|
328
|
+
fullname: string;
|
|
329
|
+
title: string;
|
|
330
|
+
createdAt: Date;
|
|
331
|
+
createdBy?: UserInfo;
|
|
332
|
+
updatedAt: Date;
|
|
333
|
+
updatedBy?: UserInfo;
|
|
334
|
+
commentedAt?: Date;
|
|
335
|
+
commentedBy?: UserInfo;
|
|
336
|
+
parentName?: string;
|
|
337
|
+
parentCategory?: string;
|
|
338
|
+
parentFullname?: string;
|
|
339
|
+
parentTitle?: string;
|
|
340
|
+
content?: string;
|
|
341
|
+
tags: string[];
|
|
342
|
+
hiddenTags: string[];
|
|
343
|
+
formData?: Record<string, string>;
|
|
344
|
+
formRaw?: Record<string, string>;
|
|
345
|
+
formLabel?: Record<string, string>;
|
|
346
|
+
formHint?: Record<string, string>;
|
|
347
|
+
children: number;
|
|
348
|
+
comments: number;
|
|
349
|
+
size: number;
|
|
350
|
+
rating: number;
|
|
351
|
+
ratingVotes: number;
|
|
352
|
+
ratingPercent?: number;
|
|
353
|
+
revisions: number;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Site context information
|
|
357
|
+
*/
|
|
358
|
+
interface SiteContext {
|
|
359
|
+
title: string;
|
|
360
|
+
name: string;
|
|
361
|
+
domain: string;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* External data for a single ListPages module
|
|
365
|
+
*/
|
|
366
|
+
interface ListPagesExternalData {
|
|
367
|
+
pages: PageData[];
|
|
368
|
+
totalCount: number;
|
|
369
|
+
site: SiteContext;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Callback to fetch data for a ListPages module
|
|
373
|
+
*
|
|
374
|
+
* Called by resolveModules for each ListPages module in the AST.
|
|
375
|
+
* Receives a normalized query with all @URL parameters resolved.
|
|
376
|
+
* Return null/undefined to skip the module (outputs nothing).
|
|
377
|
+
*
|
|
378
|
+
* @param query - Normalized query with structured types (tags, category, order, etc.)
|
|
379
|
+
* @param requirement - Original data requirement (for accessing id, neededVariables, etc.)
|
|
380
|
+
*/
|
|
381
|
+
type ListPagesDataFetcher = (query: NormalizedListPagesQuery, requirement: ListPagesDataRequirement) => ListPagesExternalData | null | undefined | Promise<ListPagesExternalData | null | undefined>;
|
|
382
|
+
/**
|
|
383
|
+
* Context passed to compiled template
|
|
384
|
+
*/
|
|
385
|
+
interface VariableContext {
|
|
386
|
+
page: PageData;
|
|
387
|
+
index: number;
|
|
388
|
+
total: number;
|
|
389
|
+
limit?: number;
|
|
390
|
+
site: SiteContext;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Compiled template function
|
|
394
|
+
*/
|
|
395
|
+
type CompiledTemplate = (ctx: VariableContext) => string;
|
|
396
|
+
/**
|
|
397
|
+
* Normalized tags selector
|
|
398
|
+
*/
|
|
399
|
+
interface NormalizedTags {
|
|
400
|
+
/** AND conditions - pages must have ALL of these tags (+tag) */
|
|
401
|
+
all: string[];
|
|
402
|
+
/** OR conditions - pages must have ANY of these tags (no prefix) */
|
|
403
|
+
any: string[];
|
|
404
|
+
/** NOT conditions - pages must NOT have these tags (-tag) */
|
|
405
|
+
none: string[];
|
|
406
|
+
/** Special selector */
|
|
407
|
+
special: "same-visible" | "same-all" | "none" | null;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Normalized category selector
|
|
411
|
+
*/
|
|
412
|
+
interface NormalizedCategory {
|
|
413
|
+
/** Categories to include */
|
|
414
|
+
include: string[];
|
|
415
|
+
/** Categories to exclude (-category) */
|
|
416
|
+
exclude: string[];
|
|
417
|
+
/** Select all categories (*) */
|
|
418
|
+
all: boolean;
|
|
419
|
+
/** Select current category (.) */
|
|
420
|
+
current: boolean;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Order field options
|
|
424
|
+
*/
|
|
425
|
+
type OrderField = "created_at" | "updated_at" | "title" | "fullname" | "rating" | "votes" | "revisions" | "comments" | "size" | "random";
|
|
426
|
+
/**
|
|
427
|
+
* Order direction
|
|
428
|
+
*/
|
|
429
|
+
type OrderDirection = "asc" | "desc";
|
|
430
|
+
/**
|
|
431
|
+
* Normalized order specification
|
|
432
|
+
*/
|
|
433
|
+
interface NormalizedOrder {
|
|
434
|
+
field: OrderField;
|
|
435
|
+
direction: OrderDirection;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Normalized parent selector
|
|
439
|
+
*/
|
|
440
|
+
type NormalizedParent = {
|
|
441
|
+
type: "none";
|
|
442
|
+
} | {
|
|
443
|
+
type: "same";
|
|
444
|
+
} | {
|
|
445
|
+
type: "different";
|
|
446
|
+
} | {
|
|
447
|
+
type: "children";
|
|
448
|
+
} | {
|
|
449
|
+
type: "page";
|
|
450
|
+
name: string;
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* Date comparison operators
|
|
454
|
+
*/
|
|
455
|
+
type DateComparisonOp = "=" | "<" | ">" | "<=" | ">=" | "<>";
|
|
456
|
+
/**
|
|
457
|
+
* Normalized date selector
|
|
458
|
+
*/
|
|
459
|
+
type NormalizedDateSelector = {
|
|
460
|
+
type: "year";
|
|
461
|
+
year: number;
|
|
462
|
+
} | {
|
|
463
|
+
type: "month";
|
|
464
|
+
year: number;
|
|
465
|
+
month: number;
|
|
466
|
+
} | {
|
|
467
|
+
type: "comparison";
|
|
468
|
+
op: DateComparisonOp;
|
|
469
|
+
date: string;
|
|
470
|
+
} | {
|
|
471
|
+
type: "relative";
|
|
472
|
+
unit: "day" | "week" | "month";
|
|
473
|
+
count: number;
|
|
474
|
+
};
|
|
475
|
+
/**
|
|
476
|
+
* Numeric comparison operators
|
|
477
|
+
*/
|
|
478
|
+
type NumericComparisonOp = "=" | "<" | ">" | "<=" | ">=";
|
|
479
|
+
/**
|
|
480
|
+
* Normalized numeric selector (for rating/votes)
|
|
481
|
+
*/
|
|
482
|
+
interface NormalizedNumericSelector {
|
|
483
|
+
op: NumericComparisonOp;
|
|
484
|
+
value: number;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Fully normalized ListPages query
|
|
488
|
+
*
|
|
489
|
+
* All string fields are parsed and structured into type-safe objects.
|
|
490
|
+
* Use `normalizeQuery()` to convert from `ListPagesQuery`.
|
|
491
|
+
*
|
|
492
|
+
* Note: This is structural normalization, not full validation.
|
|
493
|
+
* Invalid inputs are either rejected (return undefined) or ignored.
|
|
494
|
+
*/
|
|
495
|
+
interface NormalizedListPagesQuery {
|
|
496
|
+
pagetype?: "normal" | "hidden" | "*";
|
|
497
|
+
category?: NormalizedCategory;
|
|
498
|
+
tags?: NormalizedTags;
|
|
499
|
+
parent?: NormalizedParent;
|
|
500
|
+
linkTo?: string;
|
|
501
|
+
createdAt?: NormalizedDateSelector;
|
|
502
|
+
updatedAt?: NormalizedDateSelector;
|
|
503
|
+
createdBy?: string;
|
|
504
|
+
rating?: NormalizedNumericSelector;
|
|
505
|
+
votes?: NormalizedNumericSelector;
|
|
506
|
+
name?: string;
|
|
507
|
+
fullname?: string;
|
|
508
|
+
range?: "." | "before" | "after" | "others";
|
|
509
|
+
dataFormFields?: Record<string, string>;
|
|
510
|
+
order?: NormalizedOrder;
|
|
511
|
+
offset?: number;
|
|
512
|
+
limit?: number;
|
|
513
|
+
perPage?: number;
|
|
514
|
+
reverse?: boolean;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Callback to get current page's tags
|
|
518
|
+
*
|
|
519
|
+
* Called during resolve phase to evaluate [[iftags]] conditions.
|
|
520
|
+
*
|
|
521
|
+
* @returns Array of tag names for the current page
|
|
522
|
+
*/
|
|
523
|
+
type IfTagsResolver = () => string[];
|
|
524
|
+
/**
|
|
525
|
+
* Data provider interface for resolving modules that require external data
|
|
526
|
+
*
|
|
527
|
+
* All callbacks are optional - if not provided, the corresponding
|
|
528
|
+
* module/syntax will be output as-is in the AST without resolution.
|
|
529
|
+
*
|
|
530
|
+
* Note: Include resolution is handled separately via resolveIncludes().
|
|
531
|
+
*/
|
|
532
|
+
interface DataProvider {
|
|
533
|
+
/**
|
|
534
|
+
* Fetch data for ListPages module
|
|
535
|
+
* Called during resolve phase with query parameters
|
|
536
|
+
*
|
|
537
|
+
* @security `req.query` / `req.rawAttributes` are **untrusted user input** from wikitext.
|
|
538
|
+
* When building database queries:
|
|
539
|
+
* - **NEVER** interpolate them into SQL strings
|
|
540
|
+
* - **ALWAYS** use parameterized queries / prepared statements
|
|
541
|
+
* - For `order` (ORDER BY), use a whitelist of allowed column names
|
|
542
|
+
*/
|
|
543
|
+
fetchListPages?: ListPagesDataFetcher;
|
|
544
|
+
/**
|
|
545
|
+
* Fetch data for ListUsers module
|
|
546
|
+
* Called during resolve phase with user query parameters
|
|
547
|
+
*/
|
|
548
|
+
fetchListUsers?: ListUsersDataFetcher;
|
|
549
|
+
/**
|
|
550
|
+
* Get current page's tags for iftags evaluation
|
|
551
|
+
* Called during resolve phase to evaluate [[iftags]] conditions
|
|
552
|
+
*/
|
|
553
|
+
getPageTags?: IfTagsResolver;
|
|
554
|
+
}
|
|
555
|
+
import { SyntaxTree as SyntaxTree2 } from "@wdprlib/ast";
|
|
556
|
+
/**
|
|
557
|
+
* Result of extraction including compiled templates
|
|
558
|
+
*/
|
|
559
|
+
interface ExtractionResult {
|
|
560
|
+
/** Data requirements for external fetching */
|
|
561
|
+
requirements: DataRequirements;
|
|
562
|
+
/** Pre-compiled ListPages templates keyed by module id */
|
|
563
|
+
compiledListPagesTemplates: Map<number, CompiledTemplate>;
|
|
564
|
+
/** Pre-compiled ListUsers templates keyed by module id */
|
|
565
|
+
compiledListUsersTemplates: Map<number, ListUsersCompiledTemplate>;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Extract data requirements from a parsed AST
|
|
569
|
+
*/
|
|
570
|
+
declare function extractDataRequirements(ast: SyntaxTree2): ExtractionResult;
|
|
571
|
+
/**
|
|
572
|
+
* Compile a template string into an executable function
|
|
573
|
+
*/
|
|
574
|
+
declare function compileTemplate(template: string): CompiledTemplate;
|
|
575
|
+
/**
|
|
576
|
+
* Parse tags string into structured format
|
|
577
|
+
*
|
|
578
|
+
* Syntax:
|
|
579
|
+
* - `+tag`: AND condition (must have this tag)
|
|
580
|
+
* - `-tag`: NOT condition (must not have this tag)
|
|
581
|
+
* - `tag`: OR condition (any of these tags)
|
|
582
|
+
* - `=`: same visible tags as current page
|
|
583
|
+
* - `==`: exact same tags as current page
|
|
584
|
+
* - `-`: pages with no tags
|
|
585
|
+
*/
|
|
586
|
+
declare function parseTags(value: string): NormalizedTags;
|
|
587
|
+
/**
|
|
588
|
+
* Parse category string into structured format
|
|
589
|
+
*
|
|
590
|
+
* Syntax:
|
|
591
|
+
* - `*`: all categories
|
|
592
|
+
* - `.`: current category
|
|
593
|
+
* - `-category`: exclude category
|
|
594
|
+
* - `category`: include category
|
|
595
|
+
* - Multiple categories separated by comma, semicolon, or whitespace
|
|
596
|
+
*/
|
|
597
|
+
declare function parseCategory(value: string): NormalizedCategory;
|
|
598
|
+
/**
|
|
599
|
+
* Parse order string into structured format
|
|
600
|
+
*
|
|
601
|
+
* Supports both formats:
|
|
602
|
+
* - camelCase: `dateCreatedDesc`, `titleAsc`, `ratingDesc`
|
|
603
|
+
* - Space-separated: `created_at desc`, `title asc`
|
|
604
|
+
*
|
|
605
|
+
* Default: { field: "created_at", direction: "desc" }
|
|
606
|
+
*/
|
|
607
|
+
declare function parseOrder(value: string): NormalizedOrder;
|
|
608
|
+
/**
|
|
609
|
+
* Parse parent string into structured format
|
|
610
|
+
*
|
|
611
|
+
* Syntax:
|
|
612
|
+
* - `-`: orphan pages (no parent)
|
|
613
|
+
* - `=`: sibling pages (same parent as current)
|
|
614
|
+
* - `-=`: pages with different parent
|
|
615
|
+
* - `.`: children of current page
|
|
616
|
+
* - `page-name`: children of specific page
|
|
617
|
+
*
|
|
618
|
+
* Returns undefined for empty/whitespace-only input.
|
|
619
|
+
*/
|
|
620
|
+
declare function parseParent(value: string): NormalizedParent | undefined;
|
|
621
|
+
/**
|
|
622
|
+
* Parse date selector string into structured format
|
|
623
|
+
*
|
|
624
|
+
* Syntax:
|
|
625
|
+
* - `yyyy`: year only
|
|
626
|
+
* - `yyyy.mm`: year and month
|
|
627
|
+
* - `>=yyyy.mm.dd`: comparison with date
|
|
628
|
+
* - `last 7 days`: relative date
|
|
629
|
+
*/
|
|
630
|
+
declare function parseDateSelector(value: string): NormalizedDateSelector | undefined;
|
|
631
|
+
/**
|
|
632
|
+
* Parse numeric selector string into structured format
|
|
633
|
+
*
|
|
634
|
+
* Syntax:
|
|
635
|
+
* - `5`: equals 5
|
|
636
|
+
* - `>=10`: greater than or equal to 10
|
|
637
|
+
* - `<0`: less than 0
|
|
638
|
+
*
|
|
639
|
+
* Returns undefined for non-numeric or infinite values.
|
|
640
|
+
*/
|
|
641
|
+
declare function parseNumericSelector(value: string): NormalizedNumericSelector | undefined;
|
|
642
|
+
/**
|
|
643
|
+
* Normalize a ListPagesQuery into structured types
|
|
644
|
+
*
|
|
645
|
+
* @param query - Raw query with string fields
|
|
646
|
+
* @returns Normalized query with structured types
|
|
647
|
+
*/
|
|
648
|
+
declare function normalizeQuery(query: ListPagesQuery): NormalizedListPagesQuery;
|
|
649
|
+
import { PageRef } from "@wdprlib/ast";
|
|
650
|
+
/**
|
|
651
|
+
* Callback to fetch page content for include resolution.
|
|
652
|
+
* Returns the wikitext source of the page, or null if the page does not exist.
|
|
653
|
+
*
|
|
654
|
+
* @security The fetcher is called with user-provided page references.
|
|
655
|
+
* Implementations should validate and sanitize page references before
|
|
656
|
+
* using them in database queries or file system access.
|
|
657
|
+
*/
|
|
658
|
+
type IncludeFetcher = (pageRef: PageRef) => string | null;
|
|
659
|
+
/**
|
|
660
|
+
* Options for resolveIncludes
|
|
661
|
+
*/
|
|
662
|
+
interface ResolveIncludesOptions {
|
|
663
|
+
/** Maximum recursion depth for nested includes (default: 5) */
|
|
664
|
+
maxDepth?: number;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Expand all [[include]] directives in the source text.
|
|
668
|
+
*
|
|
669
|
+
* Include directives are treated as macro expansions: `[[include page]]`
|
|
670
|
+
* is replaced with the fetched page content (after variable substitution).
|
|
671
|
+
* The result is a single expanded text that can be parsed as a whole,
|
|
672
|
+
* allowing block structures (like div) to span across include boundaries.
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```ts
|
|
676
|
+
* const expanded = resolveIncludes(source, fetcher);
|
|
677
|
+
* const ast = parse(expanded);
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
declare function resolveIncludes(source: string, fetcher: IncludeFetcher, options?: ResolveIncludesOptions): string;
|
|
681
|
+
/**
|
|
682
|
+
* Compile a template string into an executable function
|
|
683
|
+
*/
|
|
684
|
+
declare function compileListUsersTemplate(template: string): ListUsersCompiledTemplate;
|
|
685
|
+
/**
|
|
686
|
+
* Extract needed variables from a template string
|
|
687
|
+
*/
|
|
688
|
+
declare function extractListUsersVariables(template: string): ListUsersVariable[];
|
|
689
|
+
import { Element as Element5, Module as Module3 } from "@wdprlib/ast";
|
|
690
|
+
/**
|
|
691
|
+
* ListUsers module data type
|
|
692
|
+
*/
|
|
693
|
+
type ListUsersModuleData = Extract<Module3, {
|
|
694
|
+
module: "list-users";
|
|
695
|
+
}>;
|
|
696
|
+
/**
|
|
697
|
+
* Type guard for list-users module
|
|
698
|
+
*/
|
|
699
|
+
declare function isListUsersModule(module: Module3): module is ListUsersModuleData;
|
|
700
|
+
/**
|
|
701
|
+
* Resolve a single ListUsers module
|
|
702
|
+
* Note: ListUsers returns only the logged-in user
|
|
703
|
+
*/
|
|
704
|
+
declare function resolveListUsers(_module: ListUsersModuleData, data: ListUsersExternalData, compiledTemplate: ListUsersCompiledTemplate, parse: ParseFunction): Element5[];
|
|
705
|
+
import { SyntaxTree as SyntaxTree3 } from "@wdprlib/ast";
|
|
706
|
+
/**
|
|
707
|
+
* Options for resolving modules
|
|
708
|
+
*/
|
|
709
|
+
interface ResolveOptions {
|
|
710
|
+
/** Parser function for re-parsing templates */
|
|
711
|
+
parse: ParseFunction;
|
|
712
|
+
/** Pre-compiled templates for ListPages */
|
|
713
|
+
compiledListPagesTemplates: Map<number, CompiledTemplate>;
|
|
714
|
+
/** Pre-compiled templates for ListUsers */
|
|
715
|
+
compiledListUsersTemplates?: Map<number, ListUsersCompiledTemplate>;
|
|
716
|
+
/** Data requirements grouped by module type */
|
|
717
|
+
requirements: {
|
|
718
|
+
listPages?: ListPagesDataRequirement[];
|
|
719
|
+
listUsers?: ListUsersDataRequirement[];
|
|
720
|
+
};
|
|
721
|
+
/**
|
|
722
|
+
* URL path for @URL parameter resolution (HPC support)
|
|
723
|
+
* Format: "/page-name/param/value/param/value"
|
|
724
|
+
* Example: "/scp-001/offset/10/page2_limit/5"
|
|
725
|
+
*/
|
|
726
|
+
urlPath?: string;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Resolve all modules in the AST
|
|
730
|
+
*
|
|
731
|
+
* Fetches data for each module using the provided callback,
|
|
732
|
+
* then expands the modules with the fetched data.
|
|
733
|
+
*
|
|
734
|
+
* Handles:
|
|
735
|
+
* - ListPages: fetches page data and expands templates
|
|
736
|
+
* - IfTags: evaluates tag conditions and includes/excludes content
|
|
737
|
+
*
|
|
738
|
+
* @param ast - Parsed AST
|
|
739
|
+
* @param dataProvider - Callback provider to fetch data for each module
|
|
740
|
+
* @param options - Resolution options including requirements
|
|
741
|
+
*/
|
|
742
|
+
declare function resolveModules(ast: SyntaxTree3, dataProvider: DataProvider, options: ResolveOptions): Promise<SyntaxTree3>;
|
|
743
|
+
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, createPosition, createPoint, container, compileTemplate, compileListUsersTemplate, bold, Version2 as Version, VariableMap, VariableContext, UserInfo, TokenType, Token, TocEntry2 as TocEntry, TableRow, TableData, TableCell, TabData, SyntaxTree4 as SyntaxTree, SiteContext, ResolveOptions, ResolveIncludesOptions, Position2 as Position, Point, ParserOptions, Parser, 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, DefinitionListItem, DateItem, DataRequirements, DataProvider, ContainerType, ContainerData, CompiledTemplate, CollapsibleData, CodeBlockData2 as CodeBlockData, ClearFloat, AttributeMap, AnchorTarget, Alignment, AlignType };
|