@stackql/provider-utils 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackql/provider-utils",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Utilities for building StackQL providers from OpenAPI specifications.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -23,18 +23,56 @@ export function getIndefiniteArticle(resourceName) {
23
23
  return article;
24
24
  }
25
25
 
26
+ /**
27
+ * Sanitizes HTML with special handling for allowed tags and backticked content
28
+ * @param {string} text - The text to sanitize
29
+ * @return {string} - The sanitized text
30
+ */
26
31
  export function sanitizeHtml(text) {
27
- return text
32
+ if (!text) return '';
33
+
34
+ // Special handling for code tags - temporarily replace them with placeholders
35
+ // that won't get escaped in the general sanitization
36
+ let result = text
37
+ // Replace <code> tags with a safe placeholder
38
+ .replace(/<code>/g, '___CODE_OPEN___')
39
+ .replace(/<\/code>/g, '___CODE_CLOSE___');
40
+
41
+ // Then apply the general sanitization
42
+ result = result
28
43
  .replace(/{/g, '&#123;')
29
44
  .replace(/}/g, '&#125;')
30
45
  .replace(/>/g, '&gt;')
31
46
  .replace(/</g, '&lt;')
32
47
  // edge case
33
48
  .replace(/&#125;_&#123;/g, '&#125;&#95;&#123;')
34
- .replace(/\n/g, '<br />')
49
+ .replace(/\n/g, '<br />');
50
+
51
+ // Fix 1: Replace &lt;br&gt;, &lt;br/&gt;, &lt;p&gt;, &lt;/p&gt; back to their literal HTML tags
52
+ // Make sure <br> is always self-closing for MDX compatibility
53
+ result = result
54
+ .replace(/&lt;br\s*\/?&gt;/gi, '<br />')
55
+ .replace(/&lt;p&gt;/gi, '<p>')
56
+ .replace(/&lt;\/p&gt;/gi, '</p>');
57
+
58
+ // Fix 2: Find any &lt; or &gt; inside backticks and convert them back to < and >
59
+ // We need to handle the backtick content by finding pairs of backticks
60
+ result = result.replace(/`([^`]*)`/g, (match, content) => {
61
+ // Convert &lt; and &gt; back to < and > only within backticked content
62
+ const fixedContent = content
63
+ .replace(/&lt;/g, '<')
64
+ .replace(/&gt;/g, '>');
65
+ return '`' + fixedContent + '`';
66
+ });
67
+
68
+ // Finally, restore the code tags
69
+ result = result
70
+ .replace(/___CODE_OPEN___/g, '<code>')
71
+ .replace(/___CODE_CLOSE___/g, '</code>');
72
+
73
+ return result;
35
74
  }
36
75
 
37
-
38
76
  export function getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, sqlVerb) {
39
77
  const methods = {};
40
78
 
@@ -215,7 +253,12 @@ function formatProperties(respProps) {
215
253
  if (typeof fieldValue != 'string') {
216
254
  continue;
217
255
  } else {
218
- additionalDescriptionPaths.push(`${fieldName}: ${String(fieldValue)}`);
256
+ // Specifically wrap pattern fields in code tags
257
+ if (fieldName === 'pattern') {
258
+ additionalDescriptionPaths.push(`${fieldName}: <code>${String(fieldValue)}</code>`);
259
+ } else {
260
+ additionalDescriptionPaths.push(`${fieldName}: ${String(fieldValue)}`);
261
+ }
219
262
  }
220
263
  }
221
264
 
@@ -224,7 +267,6 @@ function formatProperties(respProps) {
224
267
  // Store formatted property details
225
268
  allProperties[propName] = {
226
269
  type: typeString,
227
- // description: escapeHtml(fullDescription),
228
270
  description: fullDescription
229
271
  };
230
272
  }
@@ -65,11 +65,11 @@ function retServiceNameAndDesc(providerName, opItem, pathKey, svcDiscriminator,
65
65
  else if (svcDiscriminator === "path") {
66
66
  const pathParts = pathKey.replace(/^\//, '').split('/');
67
67
  if (pathParts.length > 0) {
68
- // Find the first path segment that is not 'api' or 'v{number}'
68
+ // Find the first path segment that is not 'api', 'v{number}', or '{apiVersion}'
69
69
  for (const part of pathParts) {
70
70
  const lowerPart = part.toLowerCase();
71
- // Skip if it's 'api' or matches version pattern 'v1', 'v2', etc.
72
- if (lowerPart === 'api' || /^v\d+$/.test(lowerPart)) {
71
+ // Skip if it's 'api', matches version pattern 'v1', 'v2', etc., or is '{apiVersion}'
72
+ if (lowerPart === 'api' || /^v\d+$/.test(lowerPart) || /^\{.*version\}$/i.test(part)) {
73
73
  continue;
74
74
  }
75
75
  service = lowerPart.replace(/-/g, '_').replace(/ /g, '_').replace(/\./g, '_');
@@ -78,7 +78,7 @@ function retServiceNameAndDesc(providerName, opItem, pathKey, svcDiscriminator,
78
78
  serviceDesc = `${providerName} ${service} API`;
79
79
  }
80
80
  }
81
-
81
+
82
82
  // Check if service should be skipped
83
83
  if (service === "skip") {
84
84
  return ["skip", ""];
package/src/utils.js CHANGED
@@ -9,7 +9,7 @@ import logger from './logger.js';
9
9
  */
10
10
  export function camelToSnake(name) {
11
11
  const s1 = name.replace(/([a-z0-9])([A-Z][a-z]+)/g, '$1_$2');
12
- return s1.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
12
+ return s1.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase().replace(/-/g, '_');
13
13
  }
14
14
 
15
15
  /**