@gtkx/gir 0.9.2 → 0.9.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/doc-sanitizer.ts +102 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/gir",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "GObject Introspection file parser for GTKX",
5
5
  "keywords": [
6
6
  "gtk",
@@ -127,7 +127,12 @@ function parseGirLink(type: string, reference: string): GirLink | undefined {
127
127
  };
128
128
  }
129
129
 
130
- function formatGirLinkForTsDoc(link: GirLink): string {
130
+ interface LinkFormatOptions {
131
+ linkStyle: "namespaced" | "prefixed";
132
+ currentNamespace: string | undefined;
133
+ }
134
+
135
+ function formatGirLinkForTsDoc(link: GirLink, options: LinkFormatOptions): string {
131
136
  let displayText: string;
132
137
  if (link.member) {
133
138
  displayText = `${link.target}.${link.member}`;
@@ -135,7 +140,17 @@ function formatGirLinkForTsDoc(link: GirLink): string {
135
140
  displayText = link.target;
136
141
  }
137
142
 
138
- const linkTarget = link.namespace ? `${link.namespace}.${displayText}` : displayText;
143
+ let linkTarget: string;
144
+ if (options.linkStyle === "prefixed") {
145
+ const effectiveNamespace = link.namespace ?? options.currentNamespace;
146
+ if (effectiveNamespace && effectiveNamespace !== "Gtk") {
147
+ linkTarget = `${effectiveNamespace}${displayText}`;
148
+ } else {
149
+ linkTarget = displayText;
150
+ }
151
+ } else {
152
+ linkTarget = link.namespace ? `${link.namespace}.${displayText}` : displayText;
153
+ }
139
154
 
140
155
  switch (link.type) {
141
156
  case "class":
@@ -171,37 +186,37 @@ function formatGirLinkForTsDoc(link: GirLink): string {
171
186
  }
172
187
  }
173
188
 
174
- function convertGirLinks(text: string): string {
189
+ function convertGirLinks(text: string, options: LinkFormatOptions): string {
175
190
  return text.replace(GIR_LINK_PATTERN, (_, type: string, reference: string) => {
176
191
  const link = parseGirLink(type, reference);
177
192
  if (!link) {
178
193
  return `\`${reference}\``;
179
194
  }
180
- return formatGirLinkForTsDoc(link);
195
+ return formatGirLinkForTsDoc(link, options);
181
196
  });
182
197
  }
183
198
 
184
- const NAMESPACE_TO_DOCS_PATH: Record<string, string> = {
185
- Gtk: "gtk4",
186
- Gdk: "gdk4",
187
- Gsk: "gsk4",
188
- Adw: "adw1",
189
- GLib: "glib",
190
- GObject: "gobject",
191
- Gio: "gio",
192
- Pango: "Pango",
193
- PangoCairo: "PangoCairo",
194
- GdkPixbuf: "gdk-pixbuf",
195
- Cairo: "cairo",
199
+ const GTK_DOCS_BASE_URLS: Record<string, string> = {
200
+ Gtk: "https://docs.gtk.org/gtk4",
201
+ Gdk: "https://docs.gtk.org/gdk4",
202
+ Gsk: "https://docs.gtk.org/gsk4",
203
+ GLib: "https://docs.gtk.org/glib",
204
+ GObject: "https://docs.gtk.org/gobject",
205
+ Gio: "https://docs.gtk.org/gio",
206
+ Pango: "https://docs.gtk.org/Pango",
207
+ PangoCairo: "https://docs.gtk.org/PangoCairo",
208
+ GdkPixbuf: "https://docs.gtk.org/gdk-pixbuf",
209
+ Cairo: "https://docs.gtk.org/cairo",
210
+ Adw: "https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest",
196
211
  };
197
212
 
198
213
  function getDocsBaseUrl(namespace: string | undefined): string {
199
214
  if (!namespace) {
200
215
  return "https://docs.gtk.org/gtk4";
201
216
  }
202
- const docsPath = NAMESPACE_TO_DOCS_PATH[namespace];
203
- if (docsPath) {
204
- return `https://docs.gtk.org/${docsPath}`;
217
+ const baseUrl = GTK_DOCS_BASE_URLS[namespace];
218
+ if (baseUrl) {
219
+ return baseUrl;
205
220
  }
206
221
  return `https://docs.gtk.org/${namespace.toLowerCase()}`;
207
222
  }
@@ -273,7 +288,21 @@ function convertAtAnnotations(text: string): string {
273
288
  }
274
289
 
275
290
  function escapeXmlStyleTags(text: string): string {
276
- return text.replace(/<(\/?)(child|object|property|signal|template|style|item|attribute)>/gi, "`<$1$2>`");
291
+ const codeBlockPattern = /```[\s\S]*?```/g;
292
+ const codeBlocks: string[] = [];
293
+
294
+ let processed = text.replace(codeBlockPattern, (match) => {
295
+ codeBlocks.push(match);
296
+ return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
297
+ });
298
+
299
+ processed = processed.replace(/<(\/?)(child|object|property|signal|template|style|item|attribute)>/gi, "`<$1$2>`");
300
+
301
+ for (let i = 0; i < codeBlocks.length; i++) {
302
+ processed = processed.replace(`__CODE_BLOCK_${i}__`, codeBlocks[i] ?? "");
303
+ }
304
+
305
+ return processed;
277
306
  }
278
307
 
279
308
  function cleanupWhitespace(text: string): string {
@@ -282,9 +311,44 @@ function cleanupWhitespace(text: string): string {
282
311
  return result.trim();
283
312
  }
284
313
 
314
+ interface CodeBlockProtection {
315
+ text: string;
316
+ restore: (formatted: string, linePrefix: string) => string;
317
+ }
318
+
319
+ function protectCodeBlocks(text: string): CodeBlockProtection {
320
+ const codeBlockPattern = /```[\s\S]*?```/g;
321
+ const codeBlocks: string[] = [];
322
+
323
+ const processed = text.replace(codeBlockPattern, (match) => {
324
+ codeBlocks.push(match);
325
+ return `__PROTECTED_CODE_BLOCK_${codeBlocks.length - 1}__`;
326
+ });
327
+
328
+ const restore = (formatted: string, linePrefix: string): string => {
329
+ let result = formatted;
330
+ for (let i = 0; i < codeBlocks.length; i++) {
331
+ const placeholder = `__PROTECTED_CODE_BLOCK_${i}__`;
332
+ const codeBlock = codeBlocks[i];
333
+ if (codeBlock === undefined) continue;
334
+
335
+ const codeLines = codeBlock.split("\n");
336
+ const prefixedCodeLines = codeLines.map((line, index) => {
337
+ if (index === 0) return line;
338
+ return `${linePrefix}${line}`;
339
+ });
340
+ result = result.replace(placeholder, prefixedCodeLines.join("\n"));
341
+ }
342
+ return result;
343
+ };
344
+
345
+ return { text: processed, restore };
346
+ }
347
+
285
348
  export interface SanitizeDocOptions {
286
349
  escapeXmlTags?: boolean;
287
350
  namespace?: string;
351
+ linkStyle?: "namespaced" | "prefixed";
288
352
  }
289
353
 
290
354
  export function sanitizeDoc(doc: string, options: SanitizeDocOptions = {}): string {
@@ -295,7 +359,12 @@ export function sanitizeDoc(doc: string, options: SanitizeDocOptions = {}): stri
295
359
  result = convertMarkdownImageUrls(result, baseUrl);
296
360
  result = convertKbdElements(result);
297
361
  result = stripHtmlLinks(result);
298
- result = convertGirLinks(result);
362
+
363
+ const linkFormatOptions: LinkFormatOptions = {
364
+ linkStyle: options.linkStyle ?? "namespaced",
365
+ currentNamespace: options.namespace,
366
+ };
367
+ result = convertGirLinks(result, linkFormatOptions);
299
368
  result = convertAtAnnotations(result);
300
369
 
301
370
  if (options.escapeXmlTags) {
@@ -317,15 +386,19 @@ export function formatDoc(doc: string | undefined, indent: string = "", options:
317
386
  return "";
318
387
  }
319
388
 
320
- const lines = sanitized.split("\n").map((line) => line.trim());
389
+ const { text: protectedText, restore } = protectCodeBlocks(sanitized);
390
+
391
+ const lines = protectedText.split("\n").map((line) => line.trim());
321
392
  const firstLine = lines[0] ?? "";
322
393
 
323
394
  if (lines.length === 1 && firstLine.length < 80) {
324
- return `${indent}/** ${firstLine} */\n`;
395
+ const result = `${indent}/** ${firstLine} */\n`;
396
+ return restore(result, `${indent} * `);
325
397
  }
326
398
 
327
399
  const formattedLines = lines.map((line) => `${indent} * ${line}`);
328
- return `${indent}/**\n${formattedLines.join("\n")}\n${indent} */\n`;
400
+ const result = `${indent}/**\n${formattedLines.join("\n")}\n${indent} */\n`;
401
+ return restore(result, `${indent} * `);
329
402
  }
330
403
 
331
404
  interface DocParameter {
@@ -347,9 +420,11 @@ export function formatMethodDoc(
347
420
  }
348
421
 
349
422
  const lines: string[] = [];
423
+ let protection: CodeBlockProtection | undefined;
350
424
 
351
425
  if (sanitizedDoc) {
352
- for (const line of sanitizedDoc.split("\n")) {
426
+ protection = protectCodeBlocks(sanitizedDoc);
427
+ for (const line of protection.text.split("\n")) {
353
428
  lines.push(` * ${line.trim()}`);
354
429
  }
355
430
  }
@@ -366,5 +441,6 @@ export function formatMethodDoc(
366
441
  return "";
367
442
  }
368
443
 
369
- return `${indent}/**\n${indent}${lines.join(`\n${indent}`)}\n${indent} */\n`;
444
+ const result = `${indent}/**\n${indent}${lines.join(`\n${indent}`)}\n${indent} */\n`;
445
+ return protection ? protection.restore(result, `${indent} * `) : result;
370
446
  }