AtlatestRepositorysigil-docs

sigil-docs / tree / src / sigil / docslookup.sgl

1;;; (sigil docs lookup) - JSON-based Documentation Lookup
2;;;
3;;; Loads and queries documentation from JSON files generated during
4;;; compilation. JSON doc files are co-located with .sgb bytecode files
5;;; and are found using the same load path search as module loading.
6;;;
7;;; Example:
8;;; (load-module-details '(sigil string))
9;;; => <module-details> struct with exports list
10;;;
11;;; (get-export-details '(sigil string) 'string-split)
12;;; => <export-details> struct with name, kind, doc, signature
14(define-library (sigil docs lookup)
15 (import (sigil string)
16 (sigil path)
17 (sigil fs)
18 (sigil io)
19 (sigil json)
20 (sigil resources)
21 (sigil docs types))
22 (export
23 ;; Re-export types for convenience
24 module-details
25 module-details?
26 module-details-name
27 module-details-file
28 module-details-package
29 module-details-description
30 module-details-exports
31 module-details-syntaxes
32 module-details-examples
34 export-details
35 export-details?
36 export-details-name
37 export-details-kind
38 export-details-signature
39 export-details-description
40 export-details-examples
41 export-details-source-module
42 export-details-line
44 syntax-details
45 syntax-details?
46 syntax-details-name
47 syntax-details-patterns
48 syntax-details-description
49 syntax-details-examples
51 ;; Core lookup functions
52 load-module-details
53 get-export-details
54 get-module-description
56 ;; Path utilities
57 find-doc-file
58 module-name->doc-path
60 ;; Cache management
61 clear-doc-cache)
63 (begin
65 ;; ============================================================
66 ;; Documentation Cache
67 ;; ============================================================
69 ;; Cache of loaded module details: module-name -> module-details struct
70 (define *doc-cache* '())
72 ;;; Clear the documentation cache.
73 ;;;
74 ;;; Use this to force reloading of documentation files after
75 ;;; they have been regenerated.
76 (define (clear-doc-cache)
77 (set! *doc-cache* '()))
79 ;; Look up in cache
80 (define (cache-lookup module-name)
81 (let ((entry (assoc module-name *doc-cache*)))
82 (if entry (cdr entry) #f)))
84 ;; Add to cache
85 (define (cache-store module-name details)
86 (set! *doc-cache* (cons (cons module-name details) *doc-cache*))
87 details)
89 ;; ============================================================
90 ;; Path Resolution
91 ;; ============================================================
93 ;;; Convert a module name to its documentation file path (relative).
94 ;;;
95 ;;; The path matches the .sgb bytecode location but with .json extension.
96 (define (module-name->doc-path module-name)
97 (string-append
98 (string-join (map symbol->string module-name) "/")
99 ".json"))
101 ;;; Check if documentation exists for a module.
102 ;;;
103 ;;; Uses the unified resource resolution (project -> bundle -> system).
104 (define (find-doc-file module-name)
105 (let ((relative-path (module-name->doc-path module-name)))
106 (if (resource-exists? 'lib relative-path)
107 relative-path
108 #f)))
110 ;; ============================================================
111 ;; JSON to Struct Conversion
112 ;; ============================================================
114 ;; Convert JSON export dict to export-details struct
115 ;; Note: JSON parser creates keyword symbols (name:, kind:, etc.)
116 (define (json->export-details json-export)
117 (export-details
118 name: (string->symbol (dict-ref json-export name: ""))
119 kind: (let ((k (dict-ref json-export kind: "variable")))
120 (string->symbol k))
121 signature: (let ((sig (dict-ref json-export signature: #f)))
122 (if (and sig (not (equal? sig 'null)))
123 sig
124 #f))
125 description: (let ((doc (dict-ref json-export description: #f)))
126 (if (and doc (not (equal? doc 'null)))
127 doc
128 #f))
129 examples: '()
130 source-module: (let ((src (dict-ref json-export source_module: #f)))
131 (if (and src (not (equal? src 'null)))
132 src
133 #f))
134 line: (let ((ln (dict-ref json-export line: 0)))
135 (if (integer? ln) ln 0))))
137 ;; Convert JSON module dict to module-details struct
138 (define (json->module-details json-doc module-name doc-path)
139 (let* ((exports-array (dict-ref json-doc exports: #f))
140 (exports (if exports-array
141 (array->list exports-array)
142 '()))
143 ;; Prefer the absolute source path emitted by the compiler
144 ;; (the "source" field); fall back to the doc path if missing.
145 (source-file (let ((s (dict-ref json-doc source: #f)))
146 (if (and s (string? s) (not (equal? s 'null)))
147 s
148 doc-path))))
149 (module-details
150 name: module-name
151 file: source-file
152 package: (let ((pkg (dict-ref json-doc package: #f)))
153 (if (and pkg (not (equal? pkg 'null)))
154 pkg
155 #f))
156 description: (let ((doc (dict-ref json-doc description: #f)))
157 (if (and doc (not (equal? doc 'null)))
158 doc
159 #f))
160 exports: (map json->export-details exports)
161 syntaxes: '()
162 examples: '())))
164 ;; ============================================================
165 ;; Loading Documentation
166 ;; ============================================================
168 ;;; Load documentation for a module from its JSON file.
169 ;;;
170 ;;; Returns a <module-details> struct, or #f if no documentation file
171 ;;; is found. The result is cached for subsequent lookups.
172 (define (load-module-details module-name)
173 ;; Check cache first
174 (let ((cached (cache-lookup module-name)))
175 (if cached
176 cached
177 ;; Not cached, try to load via resource resolution
178 (let ((doc-path (module-name->doc-path module-name)))
179 (let ((content (read-resource 'lib doc-path)))
180 (if (not content)
181 #f
182 (let* ((json-doc (json-decode content))
183 (details (json->module-details json-doc module-name doc-path)))
184 (cache-store module-name details))))))))
186 ;; ============================================================
187 ;; Querying Documentation
188 ;; ============================================================
190 ;;; Get the module-level documentation string.
191 ;;;
192 ;;; Returns the module's docstring, or #f if not found.
193 (define (get-module-description module-name)
194 (let ((details (load-module-details module-name)))
195 (if details
196 (module-details-description details)
197 #f)))
199 ;;; Get documentation for a specific export from a module.
200 ;;;
201 ;;; Returns an <export-details> struct, or #f if the module or export
202 ;;; is not found.
203 (define (get-export-details module-name export-name)
204 (let ((details (load-module-details module-name)))
205 (if (not details)
206 #f
207 (let loop ((exports (module-details-exports details)))
208 (cond
209 ((null? exports) #f)
210 ((eq? (export-details-name (car exports)) export-name)
211 (car exports))
212 (else (loop (cdr exports))))))))
214 ))