rs_web/lua/
types.rs

1//! Lua API type definitions for generating EmmyLua annotations and documentation
2//!
3//! This module provides the type registry used to generate:
4//! - EmmyLua annotations (.lua file with @param, @return, @class)
5//! - Markdown API documentation
6
7/// A Lua function definition
8#[derive(Debug, Clone)]
9pub struct LuaFunction {
10    pub name: &'static str,
11    pub module: Option<&'static str>,
12    pub description: &'static str,
13    pub params: &'static [LuaParam],
14    pub returns: &'static str,
15}
16
17/// A Lua function parameter
18#[derive(Debug, Clone)]
19pub struct LuaParam {
20    pub name: &'static str,
21    pub typ: &'static str,
22    pub description: &'static str,
23    pub optional: bool,
24}
25
26/// A Lua class/table type definition
27#[derive(Debug, Clone)]
28pub struct LuaClass {
29    pub name: &'static str,
30    pub description: &'static str,
31    pub fields: &'static [LuaField],
32}
33
34/// A field in a Lua class
35#[derive(Debug, Clone)]
36pub struct LuaField {
37    pub name: &'static str,
38    pub typ: &'static str,
39    pub description: &'static str,
40}
41
42// ============================================================================
43// CLASS DEFINITIONS
44// ============================================================================
45
46pub static LUA_CLASSES: &[LuaClass] = &[
47    LuaClass {
48        name: "FileInfo",
49        description: "File metadata",
50        fields: &[
51            LuaField {
52                name: "path",
53                typ: "string",
54                description: "Absolute path",
55            },
56            LuaField {
57                name: "name",
58                typ: "string",
59                description: "Full filename with extension",
60            },
61            LuaField {
62                name: "stem",
63                typ: "string",
64                description: "Filename without extension",
65            },
66            LuaField {
67                name: "ext",
68                typ: "string",
69                description: "File extension",
70            },
71            LuaField {
72                name: "is_dir",
73                typ: "boolean",
74                description: "Whether this is a directory",
75            },
76            LuaField {
77                name: "modified",
78                typ: "number|nil",
79                description: "Unix timestamp of last modification",
80            },
81        ],
82    },
83    LuaClass {
84        name: "FrontmatterResult",
85        description: "Result of reading frontmatter from a file. Frontmatter fields are merged to top level.",
86        fields: &[
87            LuaField {
88                name: "raw",
89                typ: "string",
90                description: "Original file content",
91            },
92            LuaField {
93                name: "content",
94                typ: "string",
95                description: "Content after frontmatter",
96            },
97            LuaField {
98                name: "title",
99                typ: "string?",
100                description: "Common frontmatter field",
101            },
102            LuaField {
103                name: "description",
104                typ: "string?",
105                description: "Common frontmatter field",
106            },
107            LuaField {
108                name: "date",
109                typ: "string?",
110                description: "Common frontmatter field",
111            },
112            LuaField {
113                name: "template",
114                typ: "string?",
115                description: "Common frontmatter field",
116            },
117            LuaField {
118                name: "[string]",
119                typ: "string|number|boolean|table|any[]",
120                description: "Additional frontmatter fields (supports nested values)",
121            },
122        ],
123    },
124    LuaClass {
125        name: "GitInfo",
126        description: "Git repository information",
127        fields: &[
128            LuaField {
129                name: "hash",
130                typ: "string",
131                description: "Full commit hash",
132            },
133            LuaField {
134                name: "short_hash",
135                typ: "string",
136                description: "Short hash (7 chars)",
137            },
138            LuaField {
139                name: "branch",
140                typ: "string|nil",
141                description: "Current branch name",
142            },
143            LuaField {
144                name: "author",
145                typ: "string|nil",
146                description: "Commit author",
147            },
148            LuaField {
149                name: "date",
150                typ: "string|nil",
151                description: "Commit date (YYYY-MM-DD)",
152            },
153            LuaField {
154                name: "dirty",
155                typ: "boolean",
156                description: "Has uncommitted changes",
157            },
158        ],
159    },
160    LuaClass {
161        name: "ImageDimensions",
162        description: "Image dimensions",
163        fields: &[
164            LuaField {
165                name: "width",
166                typ: "number",
167                description: "Image width in pixels",
168            },
169            LuaField {
170                name: "height",
171                typ: "number",
172                description: "Image height in pixels",
173            },
174        ],
175    },
176    LuaClass {
177        name: "ImageResizeOptions",
178        description: "Options for image_resize",
179        fields: &[
180            LuaField {
181                name: "width",
182                typ: "number",
183                description: "Target width in pixels",
184            },
185            LuaField {
186                name: "height",
187                typ: "number?",
188                description: "Target height (maintains aspect ratio if omitted)",
189            },
190            LuaField {
191                name: "quality",
192                typ: "number?",
193                description: "Quality 0-100 for lossy formats (default: 85)",
194            },
195        ],
196    },
197    LuaClass {
198        name: "ImageConvertOptions",
199        description: "Options for image_convert",
200        fields: &[
201            LuaField {
202                name: "format",
203                typ: "string?",
204                description: "Target format: 'webp'|'png'|'jpg' (default: from extension)",
205            },
206            LuaField {
207                name: "quality",
208                typ: "number?",
209                description: "Quality 0-100 for lossy formats (default: 85)",
210            },
211        ],
212    },
213    LuaClass {
214        name: "ImageOptimizeOptions",
215        description: "Options for image_optimize",
216        fields: &[LuaField {
217            name: "quality",
218            typ: "number?",
219            description: "Quality 0-100 (default: 85)",
220        }],
221    },
222    LuaClass {
223        name: "BuildCssOptions",
224        description: "Options for build_css",
225        fields: &[LuaField {
226            name: "minify",
227            typ: "boolean?",
228            description: "Minify output CSS (default: false)",
229        }],
230    },
231    LuaClass {
232        name: "MarkdownEvent",
233        description: "Markdown AST event for transformation",
234        fields: &[
235            LuaField {
236                name: "type",
237                typ: "string",
238                description: "Event type: 'text'|'html'|'code'|'start'|'end'|'softbreak'|'hardbreak'|'rule'",
239            },
240            LuaField {
241                name: "content",
242                typ: "string|nil",
243                description: "Text/HTML/code content",
244            },
245            LuaField {
246                name: "tag",
247                typ: "string|nil",
248                description: "Tag name for start/end events",
249            },
250            LuaField {
251                name: "level",
252                typ: "number|nil",
253                description: "Heading level (1-6)",
254            },
255            LuaField {
256                name: "url",
257                typ: "string|nil",
258                description: "Link/image URL",
259            },
260            LuaField {
261                name: "title",
262                typ: "string|nil",
263                description: "Link/image title",
264            },
265        ],
266    },
267    LuaClass {
268        name: "MarkdownContext",
269        description: "Context information during markdown parsing",
270        fields: &[
271            LuaField {
272                name: "in_paragraph",
273                typ: "boolean",
274                description: "Inside paragraph",
275            },
276            LuaField {
277                name: "in_heading",
278                typ: "boolean",
279                description: "Inside heading",
280            },
281            LuaField {
282                name: "in_list",
283                typ: "boolean",
284                description: "Inside list",
285            },
286            LuaField {
287                name: "in_list_item",
288                typ: "boolean",
289                description: "Inside list item",
290            },
291            LuaField {
292                name: "in_blockquote",
293                typ: "boolean",
294                description: "Inside blockquote",
295            },
296            LuaField {
297                name: "in_link",
298                typ: "boolean",
299                description: "Inside link",
300            },
301            LuaField {
302                name: "in_emphasis",
303                typ: "boolean",
304                description: "Inside emphasis",
305            },
306            LuaField {
307                name: "in_strong",
308                typ: "boolean",
309                description: "Inside strong",
310            },
311            LuaField {
312                name: "in_code_block",
313                typ: "boolean",
314                description: "Inside code block",
315            },
316            LuaField {
317                name: "in_table",
318                typ: "boolean",
319                description: "Inside table",
320            },
321            LuaField {
322                name: "heading_level",
323                typ: "number",
324                description: "Current heading level (0 if not in heading)",
325            },
326            LuaField {
327                name: "list_depth",
328                typ: "number",
329                description: "Nesting depth of lists",
330            },
331        ],
332    },
333    LuaClass {
334        name: "CoroTask",
335        description: "Coroutine task wrapper for cooperative multitasking",
336        fields: &[
337            LuaField {
338                name: "_co",
339                typ: "thread",
340                description: "Internal coroutine",
341            },
342            LuaField {
343                name: "_completed",
344                typ: "boolean",
345                description: "Whether task has completed",
346            },
347            LuaField {
348                name: "_result",
349                typ: "any",
350                description: "Task result",
351            },
352        ],
353    },
354    LuaClass {
355        name: "AsyncTask",
356        description: "Async task handle for tokio-backed I/O operations",
357        fields: &[LuaField {
358            name: "is_completed",
359            typ: "fun(): boolean",
360            description: "Check if task has completed",
361        }],
362    },
363    LuaClass {
364        name: "FetchResponse",
365        description: "HTTP response from async.fetch",
366        fields: &[
367            LuaField {
368                name: "status",
369                typ: "number",
370                description: "HTTP status code",
371            },
372            LuaField {
373                name: "ok",
374                typ: "boolean",
375                description: "Whether request was successful (2xx)",
376            },
377            LuaField {
378                name: "body",
379                typ: "string",
380                description: "Response body as string",
381            },
382            LuaField {
383                name: "headers",
384                typ: "table<string, string>",
385                description: "Response headers",
386            },
387            LuaField {
388                name: "json",
389                typ: "fun(): table",
390                description: "Parse body as JSON",
391            },
392        ],
393    },
394    LuaClass {
395        name: "FetchOptions",
396        description: "Options for async.fetch",
397        fields: &[
398            LuaField {
399                name: "method",
400                typ: "string?",
401                description: "HTTP method: GET|POST|PUT|DELETE|PATCH|HEAD (default: GET)",
402            },
403            LuaField {
404                name: "headers",
405                typ: "table<string, string>?",
406                description: "Request headers",
407            },
408            LuaField {
409                name: "body",
410                typ: "string|table?",
411                description: "Request body (table will be JSON encoded)",
412            },
413            LuaField {
414                name: "timeout",
415                typ: "number?",
416                description: "Timeout in seconds",
417            },
418        ],
419    },
420    LuaClass {
421        name: "EncryptedData",
422        description: "Encrypted content data from crypt.encrypt",
423        fields: &[
424            LuaField {
425                name: "ciphertext",
426                typ: "string",
427                description: "Base64-encoded encrypted content",
428            },
429            LuaField {
430                name: "salt",
431                typ: "string",
432                description: "Base64-encoded salt for key derivation",
433            },
434            LuaField {
435                name: "nonce",
436                typ: "string",
437                description: "Base64-encoded nonce for decryption",
438            },
439        ],
440    },
441    LuaClass {
442        name: "EncryptHtmlOptions",
443        description: "Options for crypt.encrypt_html",
444        fields: &[
445            LuaField {
446                name: "password",
447                typ: "string?",
448                description: "Encryption password (uses SITE_PASSWORD env if not provided)",
449            },
450            LuaField {
451                name: "slug",
452                typ: "string?",
453                description: "Page slug for localStorage key (default: 'page')",
454            },
455            LuaField {
456                name: "block_id",
457                typ: "string?",
458                description: "Unique block ID (auto-generated if not provided)",
459            },
460            LuaField {
461                name: "own_password",
462                typ: "boolean?",
463                description: "Whether block has its own password (default: false)",
464            },
465        ],
466    },
467    LuaClass {
468        name: "DirEntry",
469        description: "Directory entry from async.read_dir",
470        fields: &[
471            LuaField {
472                name: "path",
473                typ: "string",
474                description: "Full path to the entry",
475            },
476            LuaField {
477                name: "name",
478                typ: "string",
479                description: "Entry name (filename or directory name)",
480            },
481            LuaField {
482                name: "is_file",
483                typ: "boolean",
484                description: "Whether this is a file",
485            },
486            LuaField {
487                name: "is_dir",
488                typ: "boolean",
489                description: "Whether this is a directory",
490            },
491            LuaField {
492                name: "is_symlink",
493                typ: "boolean",
494                description: "Whether this is a symbolic link",
495            },
496        ],
497    },
498    LuaClass {
499        name: "FileMetadata",
500        description: "File metadata from async.metadata",
501        fields: &[
502            LuaField {
503                name: "is_file",
504                typ: "boolean",
505                description: "Whether this is a file",
506            },
507            LuaField {
508                name: "is_dir",
509                typ: "boolean",
510                description: "Whether this is a directory",
511            },
512            LuaField {
513                name: "len",
514                typ: "number",
515                description: "File size in bytes",
516            },
517            LuaField {
518                name: "readonly",
519                typ: "boolean",
520                description: "Whether file is read-only",
521            },
522            LuaField {
523                name: "modified",
524                typ: "number?",
525                description: "Unix timestamp of last modification",
526            },
527        ],
528    },
529    LuaClass {
530        name: "DateTable",
531        description: "Date as table with year, month, day fields",
532        fields: &[
533            LuaField {
534                name: "year",
535                typ: "number",
536                description: "Year (e.g., 2024)",
537            },
538            LuaField {
539                name: "month",
540                typ: "number",
541                description: "Month (1-12)",
542            },
543            LuaField {
544                name: "day",
545                typ: "number",
546                description: "Day of month (1-31)",
547            },
548        ],
549    },
550];
551
552// ============================================================================
553// FUNCTION DEFINITIONS
554// ============================================================================
555
556pub static LUA_FUNCTIONS: &[LuaFunction] = &[
557    // FILE OPERATIONS
558    LuaFunction {
559        name: "read_file",
560        module: None,
561        description: "Read file contents as string",
562        params: &[LuaParam {
563            name: "path",
564            typ: "string",
565            description: "Path to file",
566            optional: false,
567        }],
568        returns: "string|nil",
569    },
570    LuaFunction {
571        name: "write_file",
572        module: None,
573        description: "Write content to file",
574        params: &[
575            LuaParam {
576                name: "path",
577                typ: "string",
578                description: "Path to write to",
579                optional: false,
580            },
581            LuaParam {
582                name: "content",
583                typ: "string",
584                description: "Content to write",
585                optional: false,
586            },
587        ],
588        returns: "boolean",
589    },
590    LuaFunction {
591        name: "copy_file",
592        module: None,
593        description: "Copy a file (works with binary files)",
594        params: &[
595            LuaParam {
596                name: "src",
597                typ: "string",
598                description: "Source file path",
599                optional: false,
600            },
601            LuaParam {
602                name: "dest",
603                typ: "string",
604                description: "Destination file path",
605                optional: false,
606            },
607        ],
608        returns: "boolean",
609    },
610    LuaFunction {
611        name: "file_exists",
612        module: None,
613        description: "Check if file exists",
614        params: &[LuaParam {
615            name: "path",
616            typ: "string",
617            description: "Path to check",
618            optional: false,
619        }],
620        returns: "boolean",
621    },
622    LuaFunction {
623        name: "list_files",
624        module: None,
625        description: "List files in directory matching pattern",
626        params: &[
627            LuaParam {
628                name: "path",
629                typ: "string",
630                description: "Directory to search",
631                optional: false,
632            },
633            LuaParam {
634                name: "pattern",
635                typ: "string",
636                description: "Glob pattern (default: '*')",
637                optional: true,
638            },
639        ],
640        returns: "FileInfo[]",
641    },
642    LuaFunction {
643        name: "list_dirs",
644        module: None,
645        description: "List subdirectories",
646        params: &[LuaParam {
647            name: "path",
648            typ: "string",
649            description: "Directory to search",
650            optional: false,
651        }],
652        returns: "string[]",
653    },
654    LuaFunction {
655        name: "load_json",
656        module: None,
657        description: "Load and parse JSON file",
658        params: &[LuaParam {
659            name: "path",
660            typ: "string",
661            description: "Path to JSON file",
662            optional: false,
663        }],
664        returns: "table<string, any>|nil",
665    },
666    LuaFunction {
667        name: "load_yaml",
668        module: None,
669        description: "Load and parse YAML file",
670        params: &[LuaParam {
671            name: "path",
672            typ: "string",
673            description: "Path to YAML file",
674            optional: false,
675        }],
676        returns: "table<string, any>|nil",
677    },
678    LuaFunction {
679        name: "load_toml",
680        module: None,
681        description: "Load and parse TOML file",
682        params: &[LuaParam {
683            name: "path",
684            typ: "string",
685            description: "Path to TOML file",
686            optional: false,
687        }],
688        returns: "table<string, any>|nil",
689    },
690    LuaFunction {
691        name: "read_frontmatter",
692        module: None,
693        description: "Read and parse frontmatter from markdown file",
694        params: &[LuaParam {
695            name: "path",
696            typ: "string",
697            description: "Path to markdown file",
698            optional: false,
699        }],
700        returns: "FrontmatterResult|nil",
701    },
702    // SEARCH
703    LuaFunction {
704        name: "glob",
705        module: None,
706        description: "Find files matching glob pattern",
707        params: &[LuaParam {
708            name: "pattern",
709            typ: "string",
710            description: "Glob pattern (e.g., '**/*.md')",
711            optional: false,
712        }],
713        returns: "FileInfo[]",
714    },
715    LuaFunction {
716        name: "scan",
717        module: None,
718        description: "List directories in path",
719        params: &[LuaParam {
720            name: "path",
721            typ: "string",
722            description: "Directory to scan",
723            optional: false,
724        }],
725        returns: "FileInfo[]",
726    },
727    // COLLECTIONS
728    LuaFunction {
729        name: "filter",
730        module: None,
731        description: "Filter items using predicate function",
732        params: &[
733            LuaParam {
734                name: "items",
735                typ: "T[]",
736                description: "Items to filter",
737                optional: false,
738            },
739            LuaParam {
740                name: "fn",
741                typ: "fun(item: T): boolean",
742                description: "Predicate function",
743                optional: false,
744            },
745        ],
746        returns: "T[]",
747    },
748    LuaFunction {
749        name: "sort",
750        module: None,
751        description: "Sort items using comparator function",
752        params: &[
753            LuaParam {
754                name: "items",
755                typ: "T[]",
756                description: "Items to sort",
757                optional: false,
758            },
759            LuaParam {
760                name: "fn",
761                typ: "fun(a: T, b: T): boolean",
762                description: "Comparator (return true if a < b)",
763                optional: false,
764            },
765        ],
766        returns: "T[]",
767    },
768    LuaFunction {
769        name: "map",
770        module: None,
771        description: "Transform items using mapping function",
772        params: &[
773            LuaParam {
774                name: "items",
775                typ: "T[]",
776                description: "Items to transform",
777                optional: false,
778            },
779            LuaParam {
780                name: "fn",
781                typ: "fun(item: T): U",
782                description: "Mapping function",
783                optional: false,
784            },
785        ],
786        returns: "U[]",
787    },
788    LuaFunction {
789        name: "find",
790        module: None,
791        description: "Find first item where predicate returns true",
792        params: &[
793            LuaParam {
794                name: "items",
795                typ: "T[]",
796                description: "Items to search",
797                optional: false,
798            },
799            LuaParam {
800                name: "fn",
801                typ: "fun(item: T): boolean",
802                description: "Predicate function",
803                optional: false,
804            },
805        ],
806        returns: "T|nil",
807    },
808    LuaFunction {
809        name: "group_by",
810        module: None,
811        description: "Group items by key returned by key function",
812        params: &[
813            LuaParam {
814                name: "items",
815                typ: "T[]",
816                description: "Items to group",
817                optional: false,
818            },
819            LuaParam {
820                name: "fn",
821                typ: "fun(item: T): string",
822                description: "Key function",
823                optional: false,
824            },
825        ],
826        returns: "table<string, T[]>",
827    },
828    LuaFunction {
829        name: "unique",
830        module: None,
831        description: "Remove duplicates from array",
832        params: &[LuaParam {
833            name: "items",
834            typ: "T[]",
835            description: "Items to deduplicate",
836            optional: false,
837        }],
838        returns: "T[]",
839    },
840    LuaFunction {
841        name: "reverse",
842        module: None,
843        description: "Reverse array order",
844        params: &[LuaParam {
845            name: "items",
846            typ: "T[]",
847            description: "Items to reverse",
848            optional: false,
849        }],
850        returns: "T[]",
851    },
852    LuaFunction {
853        name: "take",
854        module: None,
855        description: "Take first n items from array",
856        params: &[
857            LuaParam {
858                name: "items",
859                typ: "T[]",
860                description: "Items to take from",
861                optional: false,
862            },
863            LuaParam {
864                name: "n",
865                typ: "number",
866                description: "Number of items to take",
867                optional: false,
868            },
869        ],
870        returns: "T[]",
871    },
872    LuaFunction {
873        name: "skip",
874        module: None,
875        description: "Skip first n items from array",
876        params: &[
877            LuaParam {
878                name: "items",
879                typ: "T[]",
880                description: "Items to skip from",
881                optional: false,
882            },
883            LuaParam {
884                name: "n",
885                typ: "number",
886                description: "Number of items to skip",
887                optional: false,
888            },
889        ],
890        returns: "T[]",
891    },
892    LuaFunction {
893        name: "keys",
894        module: None,
895        description: "Get all keys from a table",
896        params: &[LuaParam {
897            name: "table",
898            typ: "table<K, V>",
899            description: "Table to get keys from",
900            optional: false,
901        }],
902        returns: "K[]",
903    },
904    LuaFunction {
905        name: "values",
906        module: None,
907        description: "Get all values from a table",
908        params: &[LuaParam {
909            name: "table",
910            typ: "table<K, V>",
911            description: "Table to get values from",
912            optional: false,
913        }],
914        returns: "V[]",
915    },
916    // TEXT
917    LuaFunction {
918        name: "slugify",
919        module: None,
920        description: "Convert text to URL-friendly slug",
921        params: &[LuaParam {
922            name: "text",
923            typ: "string",
924            description: "Text to slugify",
925            optional: false,
926        }],
927        returns: "string",
928    },
929    LuaFunction {
930        name: "word_count",
931        module: None,
932        description: "Count words in text",
933        params: &[LuaParam {
934            name: "text",
935            typ: "string",
936            description: "Text to count",
937            optional: false,
938        }],
939        returns: "number",
940    },
941    LuaFunction {
942        name: "reading_time",
943        module: None,
944        description: "Calculate reading time in minutes",
945        params: &[
946            LuaParam {
947                name: "text",
948                typ: "string",
949                description: "Text to analyze",
950                optional: false,
951            },
952            LuaParam {
953                name: "wpm",
954                typ: "number",
955                description: "Words per minute (default: 200)",
956                optional: true,
957            },
958        ],
959        returns: "number",
960    },
961    LuaFunction {
962        name: "truncate",
963        module: None,
964        description: "Truncate text with optional suffix",
965        params: &[
966            LuaParam {
967                name: "text",
968                typ: "string",
969                description: "Text to truncate",
970                optional: false,
971            },
972            LuaParam {
973                name: "len",
974                typ: "number",
975                description: "Maximum length",
976                optional: false,
977            },
978            LuaParam {
979                name: "suffix",
980                typ: "string",
981                description: "Suffix to append (default: '...')",
982                optional: true,
983            },
984        ],
985        returns: "string",
986    },
987    LuaFunction {
988        name: "strip_tags",
989        module: None,
990        description: "Remove HTML tags from string",
991        params: &[LuaParam {
992            name: "html",
993            typ: "string",
994            description: "HTML content",
995            optional: false,
996        }],
997        returns: "string",
998    },
999    LuaFunction {
1000        name: "format_date",
1001        module: None,
1002        description: "Format a date string",
1003        params: &[
1004            LuaParam {
1005                name: "date",
1006                typ: "string|DateTable",
1007                description: "Date string (YYYY-MM-DD) or table {year, month, day}",
1008                optional: false,
1009            },
1010            LuaParam {
1011                name: "format",
1012                typ: "string",
1013                description: "Output format (chrono strftime)",
1014                optional: false,
1015            },
1016        ],
1017        returns: "string|nil",
1018    },
1019    LuaFunction {
1020        name: "parse_date",
1021        module: None,
1022        description: "Parse date string to table",
1023        params: &[LuaParam {
1024            name: "date_str",
1025            typ: "string",
1026            description: "Date string to parse",
1027            optional: false,
1028        }],
1029        returns: "DateTable|nil",
1030    },
1031    LuaFunction {
1032        name: "hash",
1033        module: None,
1034        description: "Hash content using xxHash64",
1035        params: &[LuaParam {
1036            name: "content",
1037            typ: "string",
1038            description: "Content to hash",
1039            optional: false,
1040        }],
1041        returns: "string",
1042    },
1043    LuaFunction {
1044        name: "hash_file",
1045        module: None,
1046        description: "Hash file contents using xxHash64",
1047        params: &[LuaParam {
1048            name: "path",
1049            typ: "string",
1050            description: "Path to file",
1051            optional: false,
1052        }],
1053        returns: "string|nil",
1054    },
1055    LuaFunction {
1056        name: "url_encode",
1057        module: None,
1058        description: "URL encode a string",
1059        params: &[LuaParam {
1060            name: "text",
1061            typ: "string",
1062            description: "Text to encode",
1063            optional: false,
1064        }],
1065        returns: "string",
1066    },
1067    LuaFunction {
1068        name: "url_decode",
1069        module: None,
1070        description: "URL decode a string",
1071        params: &[LuaParam {
1072            name: "text",
1073            typ: "string",
1074            description: "Text to decode",
1075            optional: false,
1076        }],
1077        returns: "string",
1078    },
1079    // PATH UTILITIES
1080    LuaFunction {
1081        name: "join_path",
1082        module: None,
1083        description: "Join path segments",
1084        params: &[LuaParam {
1085            name: "...",
1086            typ: "string",
1087            description: "Path segments to join",
1088            optional: false,
1089        }],
1090        returns: "string",
1091    },
1092    LuaFunction {
1093        name: "basename",
1094        module: None,
1095        description: "Get file name from path",
1096        params: &[LuaParam {
1097            name: "path",
1098            typ: "string",
1099            description: "File path",
1100            optional: false,
1101        }],
1102        returns: "string",
1103    },
1104    LuaFunction {
1105        name: "dirname",
1106        module: None,
1107        description: "Get directory from path",
1108        params: &[LuaParam {
1109            name: "path",
1110            typ: "string",
1111            description: "File path",
1112            optional: false,
1113        }],
1114        returns: "string",
1115    },
1116    LuaFunction {
1117        name: "extension",
1118        module: None,
1119        description: "Get file extension from path",
1120        params: &[LuaParam {
1121            name: "path",
1122            typ: "string",
1123            description: "File path",
1124            optional: false,
1125        }],
1126        returns: "string",
1127    },
1128    // ENV
1129    LuaFunction {
1130        name: "env",
1131        module: None,
1132        description: "Get environment variable",
1133        params: &[LuaParam {
1134            name: "name",
1135            typ: "string",
1136            description: "Variable name",
1137            optional: false,
1138        }],
1139        returns: "string|nil",
1140    },
1141    LuaFunction {
1142        name: "print",
1143        module: None,
1144        description: "Log message to build output",
1145        params: &[LuaParam {
1146            name: "...",
1147            typ: "any",
1148            description: "Values to print",
1149            optional: false,
1150        }],
1151        returns: "nil",
1152    },
1153    LuaFunction {
1154        name: "is_gitignored",
1155        module: None,
1156        description: "Check if path is gitignored",
1157        params: &[LuaParam {
1158            name: "path",
1159            typ: "string",
1160            description: "Path to check",
1161            optional: false,
1162        }],
1163        returns: "boolean",
1164    },
1165    // GIT
1166    LuaFunction {
1167        name: "git_info",
1168        module: None,
1169        description: "Get git information for repo or file",
1170        params: &[LuaParam {
1171            name: "path",
1172            typ: "string",
1173            description: "File/directory path (default: repo root)",
1174            optional: true,
1175        }],
1176        returns: "GitInfo|nil",
1177    },
1178    // CONTENT
1179    LuaFunction {
1180        name: "render_markdown",
1181        module: None,
1182        description: "Render markdown to HTML with optional AST transformation",
1183        params: &[
1184            LuaParam {
1185                name: "content",
1186                typ: "string",
1187                description: "Markdown content",
1188                optional: false,
1189            },
1190            LuaParam {
1191                name: "transform_fn",
1192                typ: "fun(event: MarkdownEvent, ctx: MarkdownContext): MarkdownEvent|nil",
1193                description: "Optional transform function",
1194                optional: true,
1195            },
1196        ],
1197        returns: "string",
1198    },
1199    LuaFunction {
1200        name: "rss_date",
1201        module: None,
1202        description: "Format date for RSS (RFC 2822)",
1203        params: &[LuaParam {
1204            name: "date_string",
1205            typ: "string",
1206            description: "Date string (YYYY-MM-DD)",
1207            optional: false,
1208        }],
1209        returns: "string|nil",
1210    },
1211    LuaFunction {
1212        name: "extract_links_markdown",
1213        module: None,
1214        description: "Extract links from markdown content",
1215        params: &[LuaParam {
1216            name: "content",
1217            typ: "string",
1218            description: "Markdown content",
1219            optional: false,
1220        }],
1221        returns: "string[]",
1222    },
1223    LuaFunction {
1224        name: "extract_links_html",
1225        module: None,
1226        description: "Extract links from HTML content",
1227        params: &[LuaParam {
1228            name: "content",
1229            typ: "string",
1230            description: "HTML content",
1231            optional: false,
1232        }],
1233        returns: "string[]",
1234    },
1235    LuaFunction {
1236        name: "extract_images_markdown",
1237        module: None,
1238        description: "Extract image paths from markdown",
1239        params: &[LuaParam {
1240            name: "content",
1241            typ: "string",
1242            description: "Markdown content",
1243            optional: false,
1244        }],
1245        returns: "string[]",
1246    },
1247    LuaFunction {
1248        name: "extract_images_html",
1249        module: None,
1250        description: "Extract image paths from HTML",
1251        params: &[LuaParam {
1252            name: "content",
1253            typ: "string",
1254            description: "HTML content",
1255            optional: false,
1256        }],
1257        returns: "string[]",
1258    },
1259    LuaFunction {
1260        name: "html_to_text",
1261        module: None,
1262        description: "Convert HTML to formatted plain text",
1263        params: &[LuaParam {
1264            name: "html",
1265            typ: "string",
1266            description: "HTML content",
1267            optional: false,
1268        }],
1269        returns: "string",
1270    },
1271    // ASSETS
1272    LuaFunction {
1273        name: "build_css",
1274        module: None,
1275        description: "Build and concatenate CSS files matching a glob pattern",
1276        params: &[
1277            LuaParam {
1278                name: "pattern",
1279                typ: "string",
1280                description: "Glob pattern (e.g., 'styles/*.css')",
1281                optional: false,
1282            },
1283            LuaParam {
1284                name: "output_path",
1285                typ: "string",
1286                description: "Output file path",
1287                optional: false,
1288            },
1289            LuaParam {
1290                name: "options",
1291                typ: "BuildCssOptions",
1292                description: "Build options (minify)",
1293                optional: true,
1294            },
1295        ],
1296        returns: "boolean",
1297    },
1298    // IMAGES
1299    LuaFunction {
1300        name: "image_dimensions",
1301        module: None,
1302        description: "Get image dimensions",
1303        params: &[LuaParam {
1304            name: "path",
1305            typ: "string",
1306            description: "Path to image",
1307            optional: false,
1308        }],
1309        returns: "ImageDimensions|nil",
1310    },
1311    LuaFunction {
1312        name: "image_resize",
1313        module: None,
1314        description: "Resize image",
1315        params: &[
1316            LuaParam {
1317                name: "input",
1318                typ: "string",
1319                description: "Input image path",
1320                optional: false,
1321            },
1322            LuaParam {
1323                name: "output",
1324                typ: "string",
1325                description: "Output image path",
1326                optional: false,
1327            },
1328            LuaParam {
1329                name: "options",
1330                typ: "ImageResizeOptions",
1331                description: "Resize options (width required, height/quality optional)",
1332                optional: false,
1333            },
1334        ],
1335        returns: "boolean",
1336    },
1337    LuaFunction {
1338        name: "image_convert",
1339        module: None,
1340        description: "Convert image format",
1341        params: &[
1342            LuaParam {
1343                name: "input",
1344                typ: "string",
1345                description: "Input image path",
1346                optional: false,
1347            },
1348            LuaParam {
1349                name: "output",
1350                typ: "string",
1351                description: "Output image path",
1352                optional: false,
1353            },
1354            LuaParam {
1355                name: "options",
1356                typ: "ImageConvertOptions",
1357                description: "Convert options (format/quality)",
1358                optional: true,
1359            },
1360        ],
1361        returns: "boolean",
1362    },
1363    LuaFunction {
1364        name: "image_optimize",
1365        module: None,
1366        description: "Optimize/compress image",
1367        params: &[
1368            LuaParam {
1369                name: "input",
1370                typ: "string",
1371                description: "Input image path",
1372                optional: false,
1373            },
1374            LuaParam {
1375                name: "output",
1376                typ: "string",
1377                description: "Output image path",
1378                optional: false,
1379            },
1380            LuaParam {
1381                name: "options",
1382                typ: "ImageOptimizeOptions",
1383                description: "Optimize options (quality)",
1384                optional: true,
1385            },
1386        ],
1387        returns: "boolean",
1388    },
1389    // CORO MODULE
1390    LuaFunction {
1391        name: "task",
1392        module: Some("coro"),
1393        description: "Create coroutine task from function",
1394        params: &[LuaParam {
1395            name: "fn",
1396            typ: "function",
1397            description: "Function to wrap",
1398            optional: false,
1399        }],
1400        returns: "CoroTask",
1401    },
1402    LuaFunction {
1403        name: "await",
1404        module: Some("coro"),
1405        description: "Run task to completion",
1406        params: &[LuaParam {
1407            name: "task",
1408            typ: "CoroTask",
1409            description: "Task to run",
1410            optional: false,
1411        }],
1412        returns: "any",
1413    },
1414    LuaFunction {
1415        name: "yield",
1416        module: Some("coro"),
1417        description: "Yield from current task",
1418        params: &[LuaParam {
1419            name: "value",
1420            typ: "any",
1421            description: "Value to yield",
1422            optional: true,
1423        }],
1424        returns: "any",
1425    },
1426    LuaFunction {
1427        name: "all",
1428        module: Some("coro"),
1429        description: "Run multiple tasks concurrently",
1430        params: &[LuaParam {
1431            name: "tasks",
1432            typ: "CoroTask[]",
1433            description: "Tasks to run",
1434            optional: false,
1435        }],
1436        returns: "any[]",
1437    },
1438    LuaFunction {
1439        name: "race",
1440        module: Some("coro"),
1441        description: "Run tasks and return first completed",
1442        params: &[LuaParam {
1443            name: "tasks",
1444            typ: "CoroTask[]",
1445            description: "Tasks to race",
1446            optional: false,
1447        }],
1448        returns: "any",
1449    },
1450    LuaFunction {
1451        name: "sleep",
1452        module: Some("coro"),
1453        description: "Sleep/delay (yields N times for cooperative scheduling)",
1454        params: &[LuaParam {
1455            name: "n",
1456            typ: "number",
1457            description: "Number of yields",
1458            optional: true,
1459        }],
1460        returns: "nil",
1461    },
1462    // PARALLEL MODULE
1463    LuaFunction {
1464        name: "load_json",
1465        module: Some("parallel"),
1466        description: "Load multiple JSON files in parallel",
1467        params: &[LuaParam {
1468            name: "paths",
1469            typ: "string[]",
1470            description: "Paths to load",
1471            optional: false,
1472        }],
1473        returns: "(table<string, any>|nil)[]",
1474    },
1475    LuaFunction {
1476        name: "read_files",
1477        module: Some("parallel"),
1478        description: "Read multiple files in parallel",
1479        params: &[LuaParam {
1480            name: "paths",
1481            typ: "string[]",
1482            description: "Paths to read",
1483            optional: false,
1484        }],
1485        returns: "(string|nil)[]",
1486    },
1487    LuaFunction {
1488        name: "file_exists",
1489        module: Some("parallel"),
1490        description: "Check multiple files exist in parallel",
1491        params: &[LuaParam {
1492            name: "paths",
1493            typ: "string[]",
1494            description: "Paths to check",
1495            optional: false,
1496        }],
1497        returns: "boolean[]",
1498    },
1499    LuaFunction {
1500        name: "load_yaml",
1501        module: Some("parallel"),
1502        description: "Load multiple YAML files in parallel",
1503        params: &[LuaParam {
1504            name: "paths",
1505            typ: "string[]",
1506            description: "Paths to load",
1507            optional: false,
1508        }],
1509        returns: "(table<string, any>|nil)[]",
1510    },
1511    LuaFunction {
1512        name: "read_frontmatter",
1513        module: Some("parallel"),
1514        description: "Parse frontmatter from multiple files in parallel",
1515        params: &[LuaParam {
1516            name: "paths",
1517            typ: "string[]",
1518            description: "Paths to parse",
1519            optional: false,
1520        }],
1521        returns: "(FrontmatterResult|nil)[]",
1522    },
1523    LuaFunction {
1524        name: "map",
1525        module: Some("parallel"),
1526        description: "Map over items (structure for parallel-ready code)",
1527        params: &[
1528            LuaParam {
1529                name: "items",
1530                typ: "T[]",
1531                description: "Items to map",
1532                optional: false,
1533            },
1534            LuaParam {
1535                name: "fn",
1536                typ: "fun(item: T): U",
1537                description: "Mapping function",
1538                optional: false,
1539            },
1540        ],
1541        returns: "U[]",
1542    },
1543    LuaFunction {
1544        name: "filter",
1545        module: Some("parallel"),
1546        description: "Filter items using predicate",
1547        params: &[
1548            LuaParam {
1549                name: "items",
1550                typ: "T[]",
1551                description: "Items to filter",
1552                optional: false,
1553            },
1554            LuaParam {
1555                name: "fn",
1556                typ: "fun(item: T): boolean",
1557                description: "Predicate function",
1558                optional: false,
1559            },
1560        ],
1561        returns: "T[]",
1562    },
1563    LuaFunction {
1564        name: "reduce",
1565        module: Some("parallel"),
1566        description: "Reduce items to single value",
1567        params: &[
1568            LuaParam {
1569                name: "items",
1570                typ: "T[]",
1571                description: "Items to reduce",
1572                optional: false,
1573            },
1574            LuaParam {
1575                name: "initial",
1576                typ: "U",
1577                description: "Initial accumulator value",
1578                optional: false,
1579            },
1580            LuaParam {
1581                name: "fn",
1582                typ: "fun(acc: U, item: T): U",
1583                description: "Reducer function",
1584                optional: false,
1585            },
1586        ],
1587        returns: "U",
1588    },
1589    // ASYNC MODULE (tokio-backed)
1590    LuaFunction {
1591        name: "fetch",
1592        module: Some("async"),
1593        description: "Fetch URL (blocking)",
1594        params: &[
1595            LuaParam {
1596                name: "url",
1597                typ: "string",
1598                description: "URL to fetch",
1599                optional: false,
1600            },
1601            LuaParam {
1602                name: "options",
1603                typ: "FetchOptions",
1604                description: "Request options",
1605                optional: true,
1606            },
1607        ],
1608        returns: "FetchResponse",
1609    },
1610    LuaFunction {
1611        name: "fetch_json",
1612        module: Some("async"),
1613        description: "Fetch URL and parse as JSON",
1614        params: &[
1615            LuaParam {
1616                name: "url",
1617                typ: "string",
1618                description: "URL to fetch",
1619                optional: false,
1620            },
1621            LuaParam {
1622                name: "options",
1623                typ: "FetchOptions",
1624                description: "Request options",
1625                optional: true,
1626            },
1627        ],
1628        returns: "table",
1629    },
1630    LuaFunction {
1631        name: "fetch_all",
1632        module: Some("async"),
1633        description: "Fetch multiple URLs concurrently",
1634        params: &[LuaParam {
1635            name: "requests",
1636            typ: "(string|{url: string, options?: FetchOptions})[]",
1637            description: "URLs or request objects",
1638            optional: false,
1639        }],
1640        returns: "FetchResponse[]",
1641    },
1642    LuaFunction {
1643        name: "spawn",
1644        module: Some("async"),
1645        description: "Spawn async fetch task for later await",
1646        params: &[
1647            LuaParam {
1648                name: "url",
1649                typ: "string",
1650                description: "URL to fetch",
1651                optional: false,
1652            },
1653            LuaParam {
1654                name: "options",
1655                typ: "FetchOptions",
1656                description: "Request options",
1657                optional: true,
1658            },
1659        ],
1660        returns: "AsyncTask",
1661    },
1662    LuaFunction {
1663        name: "await",
1664        module: Some("async"),
1665        description: "Await spawned async task",
1666        params: &[LuaParam {
1667            name: "task",
1668            typ: "AsyncTask",
1669            description: "Task to await",
1670            optional: false,
1671        }],
1672        returns: "FetchResponse",
1673    },
1674    LuaFunction {
1675        name: "await_all",
1676        module: Some("async"),
1677        description: "Await multiple async tasks",
1678        params: &[LuaParam {
1679            name: "tasks",
1680            typ: "AsyncTask[]",
1681            description: "Tasks to await",
1682            optional: false,
1683        }],
1684        returns: "FetchResponse[]",
1685    },
1686    LuaFunction {
1687        name: "read_file",
1688        module: Some("async"),
1689        description: "Read file asynchronously",
1690        params: &[LuaParam {
1691            name: "path",
1692            typ: "string",
1693            description: "File path",
1694            optional: false,
1695        }],
1696        returns: "string",
1697    },
1698    LuaFunction {
1699        name: "write_file",
1700        module: Some("async"),
1701        description: "Write file asynchronously",
1702        params: &[
1703            LuaParam {
1704                name: "path",
1705                typ: "string",
1706                description: "File path",
1707                optional: false,
1708            },
1709            LuaParam {
1710                name: "content",
1711                typ: "string",
1712                description: "Content to write",
1713                optional: false,
1714            },
1715        ],
1716        returns: "boolean",
1717    },
1718    LuaFunction {
1719        name: "read_files",
1720        module: Some("async"),
1721        description: "Read multiple files concurrently",
1722        params: &[LuaParam {
1723            name: "paths",
1724            typ: "string[]",
1725            description: "File paths",
1726            optional: false,
1727        }],
1728        returns: "(string|nil)[]",
1729    },
1730    LuaFunction {
1731        name: "load_json",
1732        module: Some("async"),
1733        description: "Load and parse JSON file asynchronously",
1734        params: &[LuaParam {
1735            name: "path",
1736            typ: "string",
1737            description: "JSON file path",
1738            optional: false,
1739        }],
1740        returns: "table",
1741    },
1742    LuaFunction {
1743        name: "copy_file",
1744        module: Some("async"),
1745        description: "Copy file asynchronously",
1746        params: &[
1747            LuaParam {
1748                name: "src",
1749                typ: "string",
1750                description: "Source path",
1751                optional: false,
1752            },
1753            LuaParam {
1754                name: "dst",
1755                typ: "string",
1756                description: "Destination path",
1757                optional: false,
1758            },
1759        ],
1760        returns: "number",
1761    },
1762    LuaFunction {
1763        name: "rename",
1764        module: Some("async"),
1765        description: "Rename/move file or directory asynchronously",
1766        params: &[
1767            LuaParam {
1768                name: "src",
1769                typ: "string",
1770                description: "Source path",
1771                optional: false,
1772            },
1773            LuaParam {
1774                name: "dst",
1775                typ: "string",
1776                description: "Destination path",
1777                optional: false,
1778            },
1779        ],
1780        returns: "boolean",
1781    },
1782    LuaFunction {
1783        name: "create_dir",
1784        module: Some("async"),
1785        description: "Create directory (including parents) asynchronously",
1786        params: &[LuaParam {
1787            name: "path",
1788            typ: "string",
1789            description: "Directory path",
1790            optional: false,
1791        }],
1792        returns: "boolean",
1793    },
1794    LuaFunction {
1795        name: "remove_file",
1796        module: Some("async"),
1797        description: "Remove file asynchronously",
1798        params: &[LuaParam {
1799            name: "path",
1800            typ: "string",
1801            description: "File path",
1802            optional: false,
1803        }],
1804        returns: "boolean",
1805    },
1806    LuaFunction {
1807        name: "remove_dir",
1808        module: Some("async"),
1809        description: "Remove directory recursively asynchronously",
1810        params: &[LuaParam {
1811            name: "path",
1812            typ: "string",
1813            description: "Directory path",
1814            optional: false,
1815        }],
1816        returns: "boolean",
1817    },
1818    LuaFunction {
1819        name: "exists",
1820        module: Some("async"),
1821        description: "Check if file/directory exists asynchronously",
1822        params: &[LuaParam {
1823            name: "path",
1824            typ: "string",
1825            description: "Path to check",
1826            optional: false,
1827        }],
1828        returns: "boolean",
1829    },
1830    LuaFunction {
1831        name: "metadata",
1832        module: Some("async"),
1833        description: "Get file metadata asynchronously",
1834        params: &[LuaParam {
1835            name: "path",
1836            typ: "string",
1837            description: "File path",
1838            optional: false,
1839        }],
1840        returns: "FileMetadata",
1841    },
1842    LuaFunction {
1843        name: "read",
1844        module: Some("async"),
1845        description: "Read file as binary data asynchronously",
1846        params: &[LuaParam {
1847            name: "path",
1848            typ: "string",
1849            description: "File path",
1850            optional: false,
1851        }],
1852        returns: "string",
1853    },
1854    LuaFunction {
1855        name: "read_dir",
1856        module: Some("async"),
1857        description: "List directory contents asynchronously",
1858        params: &[LuaParam {
1859            name: "path",
1860            typ: "string",
1861            description: "Directory path",
1862            optional: false,
1863        }],
1864        returns: "DirEntry[]",
1865    },
1866    LuaFunction {
1867        name: "canonicalize",
1868        module: Some("async"),
1869        description: "Get canonical/absolute path asynchronously",
1870        params: &[LuaParam {
1871            name: "path",
1872            typ: "string",
1873            description: "Path to canonicalize",
1874            optional: false,
1875        }],
1876        returns: "string",
1877    },
1878    // CRYPT MODULE
1879    LuaFunction {
1880        name: "encrypt",
1881        module: Some("crypt"),
1882        description: "Encrypt content using AES-256-GCM",
1883        params: &[
1884            LuaParam {
1885                name: "content",
1886                typ: "string",
1887                description: "Content to encrypt",
1888                optional: false,
1889            },
1890            LuaParam {
1891                name: "password",
1892                typ: "string",
1893                description: "Encryption password (uses SITE_PASSWORD env if not provided)",
1894                optional: true,
1895            },
1896        ],
1897        returns: "EncryptedData",
1898    },
1899    LuaFunction {
1900        name: "decrypt",
1901        module: Some("crypt"),
1902        description: "Decrypt content using AES-256-GCM",
1903        params: &[
1904            LuaParam {
1905                name: "data",
1906                typ: "EncryptedData",
1907                description: "Encrypted data table with ciphertext, salt, nonce",
1908                optional: false,
1909            },
1910            LuaParam {
1911                name: "password",
1912                typ: "string",
1913                description: "Decryption password (uses SITE_PASSWORD env if not provided)",
1914                optional: true,
1915            },
1916        ],
1917        returns: "string",
1918    },
1919    LuaFunction {
1920        name: "encrypt_html",
1921        module: Some("crypt"),
1922        description: "Encrypt content and wrap in HTML container for browser decryption",
1923        params: &[
1924            LuaParam {
1925                name: "content",
1926                typ: "string",
1927                description: "Content to encrypt (can be HTML)",
1928                optional: false,
1929            },
1930            LuaParam {
1931                name: "options",
1932                typ: "EncryptHtmlOptions",
1933                description: "Encryption options",
1934                optional: true,
1935            },
1936        ],
1937        returns: "string",
1938    },
1939];
1940
1941// ============================================================================
1942// GENERATION FUNCTIONS
1943// ============================================================================
1944
1945/// Generate EmmyLua type definitions
1946pub fn generate_emmylua() -> String {
1947    let mut output = String::new();
1948    output.push_str("---@meta rs-web\n\n");
1949    output.push_str("-- Auto-generated EmmyLua type definitions for rs-web\n");
1950    output.push_str("-- Generated with: rs-web types --lua\n");
1951    output.push_str("--\n");
1952    output.push_str("-- Usage:\n");
1953    output.push_str("--   local rs = require(\"rs-web\")\n");
1954    output.push_str("--   local content = rs.read_file(\"path/to/file.md\")\n");
1955    output.push_str("--   local html = rs.render_markdown(content)\n\n");
1956
1957    // Generate class definitions
1958    output.push_str(
1959        "-- =============================================================================\n",
1960    );
1961    output.push_str("-- TYPE DEFINITIONS\n");
1962    output.push_str(
1963        "-- =============================================================================\n\n",
1964    );
1965
1966    for class in LUA_CLASSES {
1967        output.push_str(&format!("---@class {}\n", class.name));
1968        for field in class.fields {
1969            output.push_str(&format!(
1970                "---@field {} {} {}\n",
1971                field.name, field.typ, field.description
1972            ));
1973        }
1974        output.push('\n');
1975    }
1976
1977    // Group functions by module
1978    let mut global_fns: Vec<&LuaFunction> = Vec::new();
1979    let mut coro_fns: Vec<&LuaFunction> = Vec::new();
1980    let mut parallel_fns: Vec<&LuaFunction> = Vec::new();
1981    let mut async_fns: Vec<&LuaFunction> = Vec::new();
1982    let mut crypt_fns: Vec<&LuaFunction> = Vec::new();
1983
1984    for func in LUA_FUNCTIONS {
1985        match func.module {
1986            None => global_fns.push(func),
1987            Some("coro") => coro_fns.push(func),
1988            Some("parallel") => parallel_fns.push(func),
1989            Some("async") => async_fns.push(func),
1990            Some("crypt") => crypt_fns.push(func),
1991            _ => global_fns.push(func),
1992        }
1993    }
1994
1995    // Generate coro submodule class
1996    output.push_str(
1997        "-- =============================================================================\n",
1998    );
1999    output.push_str("-- CORO SUBMODULE\n");
2000    output.push_str(
2001        "-- =============================================================================\n\n",
2002    );
2003    output.push_str("---@class RsCoroModule\n");
2004    for func in &coro_fns {
2005        let params = func
2006            .params
2007            .iter()
2008            .map(|p| {
2009                let opt = if p.optional { "?" } else { "" };
2010                format!("{}{}: {}", p.name, opt, p.typ)
2011            })
2012            .collect::<Vec<_>>()
2013            .join(", ");
2014        output.push_str(&format!(
2015            "---@field {} fun({}): {} {}\n",
2016            func.name, params, func.returns, func.description
2017        ));
2018    }
2019    output.push('\n');
2020
2021    // Generate parallel submodule class
2022    output.push_str(
2023        "-- =============================================================================\n",
2024    );
2025    output.push_str("-- PARALLEL SUBMODULE\n");
2026    output.push_str(
2027        "-- =============================================================================\n\n",
2028    );
2029    output.push_str("---@class RsParallelModule\n");
2030    for func in &parallel_fns {
2031        let params = func
2032            .params
2033            .iter()
2034            .map(|p| {
2035                let opt = if p.optional { "?" } else { "" };
2036                format!("{}{}: {}", p.name, opt, p.typ)
2037            })
2038            .collect::<Vec<_>>()
2039            .join(", ");
2040        output.push_str(&format!(
2041            "---@field {} fun({}): {} {}\n",
2042            func.name, params, func.returns, func.description
2043        ));
2044    }
2045    output.push('\n');
2046
2047    // Generate async submodule class
2048    output.push_str(
2049        "-- =============================================================================\n",
2050    );
2051    output.push_str("-- ASYNC SUBMODULE (tokio-backed)\n");
2052    output.push_str(
2053        "-- =============================================================================\n\n",
2054    );
2055    output.push_str("---@class RsAsyncModule\n");
2056    for func in &async_fns {
2057        let params = func
2058            .params
2059            .iter()
2060            .map(|p| {
2061                let opt = if p.optional { "?" } else { "" };
2062                format!("{}{}: {}", p.name, opt, p.typ)
2063            })
2064            .collect::<Vec<_>>()
2065            .join(", ");
2066        output.push_str(&format!(
2067            "---@field {} fun({}): {} {}\n",
2068            func.name, params, func.returns, func.description
2069        ));
2070    }
2071    output.push('\n');
2072
2073    // Generate crypt submodule class
2074    output.push_str(
2075        "-- =============================================================================\n",
2076    );
2077    output.push_str("-- CRYPT SUBMODULE\n");
2078    output.push_str(
2079        "-- =============================================================================\n\n",
2080    );
2081    output.push_str("---@class RsCryptModule\n");
2082    for func in &crypt_fns {
2083        let params = func
2084            .params
2085            .iter()
2086            .map(|p| {
2087                let opt = if p.optional { "?" } else { "" };
2088                format!("{}{}: {}", p.name, opt, p.typ)
2089            })
2090            .collect::<Vec<_>>()
2091            .join(", ");
2092        output.push_str(&format!(
2093            "---@field {} fun({}): {} {}\n",
2094            func.name, params, func.returns, func.description
2095        ));
2096    }
2097    output.push('\n');
2098
2099    // Generate main rs module class
2100    output.push_str(
2101        "-- =============================================================================\n",
2102    );
2103    output.push_str("-- RS-WEB MODULE\n");
2104    output.push_str(
2105        "-- =============================================================================\n\n",
2106    );
2107    output.push_str("---@class RsWebModule\n");
2108    output.push_str("---@field _VERSION string Module version\n");
2109    output.push_str("---@field _SANDBOX boolean Whether sandbox mode is enabled\n");
2110    output.push_str("---@field _PROJECT_ROOT string Project root directory\n");
2111    output.push_str("---@field coro RsCoroModule Coroutine helpers\n");
2112    output.push_str("---@field parallel RsParallelModule Parallel processing functions\n");
2113    output.push_str("---@field async RsAsyncModule Async I/O functions (tokio-backed)\n");
2114    output.push_str("---@field crypt RsCryptModule Encryption functions (AES-256-GCM)\n");
2115
2116    // Add all global functions as fields
2117    for func in &global_fns {
2118        let params = func
2119            .params
2120            .iter()
2121            .map(|p| {
2122                let opt = if p.optional { "?" } else { "" };
2123                format!("{}{}: {}", p.name, opt, p.typ)
2124            })
2125            .collect::<Vec<_>>()
2126            .join(", ");
2127        output.push_str(&format!(
2128            "---@field {} fun({}): {} {}\n",
2129            func.name, params, func.returns, func.description
2130        ));
2131    }
2132    output.push('\n');
2133
2134    // Create the rs table
2135    output.push_str("---The rs-web module\n");
2136    output.push_str("---@type RsWebModule\n");
2137    output.push_str("local rs = {}\n\n");
2138
2139    // Generate function stubs for better IDE completion
2140    output.push_str(
2141        "-- =============================================================================\n",
2142    );
2143    output.push_str("-- FUNCTION STUBS (for IDE completion)\n");
2144    output.push_str(
2145        "-- =============================================================================\n\n",
2146    );
2147
2148    for func in &global_fns {
2149        output.push_str(&format!("---{}\n", func.description));
2150        for param in func.params {
2151            let opt = if param.optional { "?" } else { "" };
2152            output.push_str(&format!(
2153                "---@param {}{} {} {}\n",
2154                param.name, opt, param.typ, param.description
2155            ));
2156        }
2157        output.push_str(&format!("---@return {}\n", func.returns));
2158
2159        let params = func
2160            .params
2161            .iter()
2162            .map(|p| p.name.to_string())
2163            .collect::<Vec<_>>()
2164            .join(", ");
2165        output.push_str(&format!("function rs.{}({}) end\n\n", func.name, params));
2166    }
2167
2168    // Coro submodule stubs
2169    output.push_str("-- Coro submodule\n");
2170    output.push_str("rs.coro = {}\n\n");
2171
2172    for func in &coro_fns {
2173        output.push_str(&format!("---{}\n", func.description));
2174        for param in func.params {
2175            let opt = if param.optional { "?" } else { "" };
2176            output.push_str(&format!(
2177                "---@param {}{} {} {}\n",
2178                param.name, opt, param.typ, param.description
2179            ));
2180        }
2181        output.push_str(&format!("---@return {}\n", func.returns));
2182
2183        let params = func
2184            .params
2185            .iter()
2186            .map(|p| p.name.to_string())
2187            .collect::<Vec<_>>()
2188            .join(", ");
2189        output.push_str(&format!(
2190            "function rs.coro.{}({}) end\n\n",
2191            func.name, params
2192        ));
2193    }
2194
2195    // Parallel submodule stubs
2196    output.push_str("-- Parallel submodule\n");
2197    output.push_str("rs.parallel = {}\n\n");
2198
2199    for func in &parallel_fns {
2200        output.push_str(&format!("---{}\n", func.description));
2201        for param in func.params {
2202            let opt = if param.optional { "?" } else { "" };
2203            output.push_str(&format!(
2204                "---@param {}{} {} {}\n",
2205                param.name, opt, param.typ, param.description
2206            ));
2207        }
2208        output.push_str(&format!("---@return {}\n", func.returns));
2209
2210        let params = func
2211            .params
2212            .iter()
2213            .map(|p| p.name.to_string())
2214            .collect::<Vec<_>>()
2215            .join(", ");
2216        output.push_str(&format!(
2217            "function rs.parallel.{}({}) end\n\n",
2218            func.name, params
2219        ));
2220    }
2221
2222    // Async submodule stubs
2223    output.push_str("-- Async submodule (tokio-backed)\n");
2224    output.push_str("rs.async = {}\n\n");
2225
2226    for func in &async_fns {
2227        output.push_str(&format!("---{}\n", func.description));
2228        for param in func.params {
2229            let opt = if param.optional { "?" } else { "" };
2230            output.push_str(&format!(
2231                "---@param {}{} {} {}\n",
2232                param.name, opt, param.typ, param.description
2233            ));
2234        }
2235        output.push_str(&format!("---@return {}\n", func.returns));
2236
2237        let params = func
2238            .params
2239            .iter()
2240            .map(|p| p.name.to_string())
2241            .collect::<Vec<_>>()
2242            .join(", ");
2243        output.push_str(&format!(
2244            "function rs.async.{}({}) end\n\n",
2245            func.name, params
2246        ));
2247    }
2248
2249    // Crypt submodule stubs
2250    output.push_str("-- Crypt submodule (AES-256-GCM encryption)\n");
2251    output.push_str("rs.crypt = {}\n\n");
2252
2253    for func in &crypt_fns {
2254        output.push_str(&format!("---{}\n", func.description));
2255        for param in func.params {
2256            let opt = if param.optional { "?" } else { "" };
2257            output.push_str(&format!(
2258                "---@param {}{} {} {}\n",
2259                param.name, opt, param.typ, param.description
2260            ));
2261        }
2262        output.push_str(&format!("---@return {}\n", func.returns));
2263
2264        let params = func
2265            .params
2266            .iter()
2267            .map(|p| p.name.to_string())
2268            .collect::<Vec<_>>()
2269            .join(", ");
2270        output.push_str(&format!(
2271            "function rs.crypt.{}({}) end\n\n",
2272            func.name, params
2273        ));
2274    }
2275
2276    output.push_str("return rs\n");
2277
2278    output
2279}
2280
2281/// Generate Markdown API documentation
2282pub fn generate_markdown() -> String {
2283    let mut output = String::new();
2284    output.push_str("# rs-web Lua API Reference\n\n");
2285    output.push_str("Auto-generated documentation for rs-web Lua functions.\n\n");
2286    output.push_str("## Usage\n\n");
2287    output.push_str("```lua\n");
2288    output.push_str("local rs = require(\"rs-web\")\n");
2289    output.push_str("local content = rs.read_file(\"path/to/file.md\")\n");
2290    output.push_str("local html = rs.render_markdown(content)\n");
2291    output.push_str("```\n\n");
2292    output.push_str("## Table of Contents\n\n");
2293    output.push_str("- [Types](#types)\n");
2294    output.push_str("- [File Operations](#file-operations)\n");
2295    output.push_str("- [Search](#search)\n");
2296    output.push_str("- [Collections](#collections)\n");
2297    output.push_str("- [Text Processing](#text-processing)\n");
2298    output.push_str("- [Path Utilities](#path-utilities)\n");
2299    output.push_str("- [Environment](#environment)\n");
2300    output.push_str("- [Git](#git)\n");
2301    output.push_str("- [Content Processing](#content-processing)\n");
2302    output.push_str("- [Image Processing](#image-processing)\n");
2303    output.push_str("- [Coro Module](#coro-module)\n");
2304    output.push_str("- [Parallel Module](#parallel-module)\n");
2305    output.push_str("- [Async Module](#async-module)\n");
2306    output.push_str("- [Crypt Module](#crypt-module)\n\n");
2307
2308    // Types section
2309    output.push_str("## Types\n\n");
2310    for class in LUA_CLASSES {
2311        output.push_str(&format!("### {}\n\n", class.name));
2312        output.push_str(&format!("{}\n\n", class.description));
2313        output.push_str("| Field | Type | Description |\n");
2314        output.push_str("|-------|------|-------------|\n");
2315        for field in class.fields {
2316            output.push_str(&format!(
2317                "| `{}` | `{}` | {} |\n",
2318                field.name, field.typ, field.description
2319            ));
2320        }
2321        output.push('\n');
2322    }
2323
2324    // Group functions by category
2325    let categories = [
2326        (
2327            "File Operations",
2328            vec![
2329                "read_file",
2330                "write_file",
2331                "copy_file",
2332                "file_exists",
2333                "list_files",
2334                "list_dirs",
2335                "load_json",
2336                "load_yaml",
2337                "load_toml",
2338                "read_frontmatter",
2339            ],
2340        ),
2341        ("Search", vec!["glob", "scan"]),
2342        (
2343            "Collections",
2344            vec![
2345                "filter", "sort", "map", "find", "group_by", "unique", "reverse", "take", "skip",
2346                "keys", "values",
2347            ],
2348        ),
2349        (
2350            "Text Processing",
2351            vec![
2352                "slugify",
2353                "word_count",
2354                "reading_time",
2355                "truncate",
2356                "strip_tags",
2357                "format_date",
2358                "parse_date",
2359                "hash",
2360                "hash_file",
2361                "url_encode",
2362                "url_decode",
2363            ],
2364        ),
2365        (
2366            "Path Utilities",
2367            vec!["join_path", "basename", "dirname", "extension"],
2368        ),
2369        ("Environment", vec!["env", "print", "is_gitignored"]),
2370        ("Git", vec!["git_info"]),
2371        (
2372            "Content Processing",
2373            vec![
2374                "render_markdown",
2375                "rss_date",
2376                "extract_links_markdown",
2377                "extract_links_html",
2378                "extract_images_markdown",
2379                "extract_images_html",
2380                "html_to_text",
2381            ],
2382        ),
2383        (
2384            "Image Processing",
2385            vec![
2386                "image_dimensions",
2387                "image_resize",
2388                "image_convert",
2389                "image_optimize",
2390            ],
2391        ),
2392        ("Assets", vec!["build_css"]),
2393    ];
2394
2395    for (cat_name, func_names) in &categories {
2396        output.push_str(&format!("## {}\n\n", cat_name));
2397
2398        for func_name in func_names {
2399            if let Some(func) = LUA_FUNCTIONS
2400                .iter()
2401                .find(|f| f.name == *func_name && f.module.is_none())
2402            {
2403                output.push_str(&format!("### `rs.{}()`\n\n", func.name));
2404                output.push_str(&format!("{}\n\n", func.description));
2405
2406                if !func.params.is_empty() {
2407                    output.push_str("**Parameters:**\n\n");
2408                    for param in func.params {
2409                        let opt = if param.optional { " (optional)" } else { "" };
2410                        output.push_str(&format!(
2411                            "- `{}`: `{}`{} - {}\n",
2412                            param.name, param.typ, opt, param.description
2413                        ));
2414                    }
2415                    output.push('\n');
2416                }
2417
2418                output.push_str(&format!("**Returns:** `{}`\n\n", func.returns));
2419            }
2420        }
2421    }
2422
2423    // Coro module
2424    output.push_str("## Coro Module\n\n");
2425    output.push_str("Coroutine-based cooperative multitasking helpers.\n\n");
2426    for func in LUA_FUNCTIONS.iter().filter(|f| f.module == Some("coro")) {
2427        output.push_str(&format!("### `rs.coro.{}()`\n\n", func.name));
2428        output.push_str(&format!("{}\n\n", func.description));
2429
2430        if !func.params.is_empty() {
2431            output.push_str("**Parameters:**\n\n");
2432            for param in func.params {
2433                let opt = if param.optional { " (optional)" } else { "" };
2434                output.push_str(&format!(
2435                    "- `{}`: `{}`{} - {}\n",
2436                    param.name, param.typ, opt, param.description
2437                ));
2438            }
2439            output.push('\n');
2440        }
2441
2442        output.push_str(&format!("**Returns:** `{}`\n\n", func.returns));
2443    }
2444
2445    // Parallel module
2446    output.push_str("## Parallel Module\n\n");
2447    output.push_str("True parallel processing with Rayon.\n\n");
2448    for func in LUA_FUNCTIONS
2449        .iter()
2450        .filter(|f| f.module == Some("parallel"))
2451    {
2452        output.push_str(&format!("### `rs.parallel.{}()`\n\n", func.name));
2453        output.push_str(&format!("{}\n\n", func.description));
2454
2455        if !func.params.is_empty() {
2456            output.push_str("**Parameters:**\n\n");
2457            for param in func.params {
2458                let opt = if param.optional { " (optional)" } else { "" };
2459                output.push_str(&format!(
2460                    "- `{}`: `{}`{} - {}\n",
2461                    param.name, param.typ, opt, param.description
2462                ));
2463            }
2464            output.push('\n');
2465        }
2466
2467        output.push_str(&format!("**Returns:** `{}`\n\n", func.returns));
2468    }
2469
2470    // Async module
2471    output.push_str("## Async Module\n\n");
2472    output.push_str("Async I/O operations backed by Tokio.\n\n");
2473    for func in LUA_FUNCTIONS.iter().filter(|f| f.module == Some("async")) {
2474        output.push_str(&format!("### `rs.async.{}()`\n\n", func.name));
2475        output.push_str(&format!("{}\n\n", func.description));
2476
2477        if !func.params.is_empty() {
2478            output.push_str("**Parameters:**\n\n");
2479            for param in func.params {
2480                let opt = if param.optional { " (optional)" } else { "" };
2481                output.push_str(&format!(
2482                    "- `{}`: `{}`{} - {}\n",
2483                    param.name, param.typ, opt, param.description
2484                ));
2485            }
2486            output.push('\n');
2487        }
2488
2489        output.push_str(&format!("**Returns:** `{}`\n\n", func.returns));
2490    }
2491
2492    // Crypt module
2493    output.push_str("## Crypt Module\n\n");
2494    output.push_str("Encryption functions using AES-256-GCM with Argon2id key derivation.\n\n");
2495    for func in LUA_FUNCTIONS.iter().filter(|f| f.module == Some("crypt")) {
2496        output.push_str(&format!("### `rs.crypt.{}()`\n\n", func.name));
2497        output.push_str(&format!("{}\n\n", func.description));
2498
2499        if !func.params.is_empty() {
2500            output.push_str("**Parameters:**\n\n");
2501            for param in func.params {
2502                let opt = if param.optional { " (optional)" } else { "" };
2503                output.push_str(&format!(
2504                    "- `{}`: `{}`{} - {}\n",
2505                    param.name, param.typ, opt, param.description
2506                ));
2507            }
2508            output.push('\n');
2509        }
2510
2511        output.push_str(&format!("**Returns:** `{}`\n\n", func.returns));
2512    }
2513
2514    output
2515}