@hubspot/ui-extensions-sdk-api-metadata 0.12.1 → 0.12.3

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.
@@ -217,6 +217,9 @@ describe('getComponentPropsDocumentation', () => {
217
217
  it('should return the correct component prop documentation for the SettingsView component', async () => {
218
218
  await runComponentPropsSnapshotTest(ComponentName.SettingsView);
219
219
  });
220
+ it('should return the correct component prop documentation for the Spacer component', async () => {
221
+ await runComponentPropsSnapshotTest(ComponentName.Spacer);
222
+ });
220
223
  it('should return the correct component prop documentation for the Stack2 component', async () => {
221
224
  await runComponentPropsSnapshotTest(ComponentName.Stack2);
222
225
  });
@@ -5,39 +5,39 @@ describe('convertHtmlToJsx', () => {
5
5
  it('should convert <br> to self-closing tag', () => {
6
6
  const input = '<strong>Hello<br>World</strong>';
7
7
  const output = convertHtmlToJsx(input);
8
- expect(output).toBe('<><strong>Hello<br/>World</strong></>');
8
+ expect(output).toBe('<><strong>Hello<br />World</strong></>');
9
9
  });
10
10
  it('should convert <hr> to self-closing tag', () => {
11
11
  const input = '<div>Section 1<hr>Section 2</div>';
12
12
  const output = convertHtmlToJsx(input);
13
- expect(output).toBe('<><div>Section 1<hr/>Section 2</div></>');
13
+ expect(output).toBe('<><div>Section 1<hr />Section 2</div></>');
14
14
  });
15
15
  it('should convert <img> to self-closing tag', () => {
16
16
  const input = '<img src="test.png">';
17
17
  const output = convertHtmlToJsx(input);
18
- expect(output).toBe('<><img src="test.png"/></>');
18
+ expect(output).toBe('<><img src="test.png" /></>');
19
19
  });
20
20
  it('should convert <input> to self-closing tag', () => {
21
21
  const input = '<input type="text" name="field">';
22
22
  const output = convertHtmlToJsx(input);
23
- expect(output).toBe('<><input type="text" name="field"/></>');
23
+ expect(output).toBe('<><input type="text" name="field" /></>');
24
24
  });
25
25
  it('should handle multiple void elements', () => {
26
26
  const input = '<div><img src="a.png"><br><img src="b.png"></div>';
27
27
  const output = convertHtmlToJsx(input);
28
- expect(output).toBe('<><div><img src="a.png"/><br/><img src="b.png"/></div></>');
28
+ expect(output).toBe('<><div><img src="a.png" /><br /><img src="b.png" /></div></>');
29
29
  });
30
30
  it('should preserve already self-closing tags', () => {
31
31
  const input = '<strong>Hello<br/>World</strong>';
32
32
  const output = convertHtmlToJsx(input);
33
- expect(output).toBe('<><strong>Hello<br/>World</strong></>');
33
+ expect(output).toBe('<><strong>Hello<br />World</strong></>');
34
34
  });
35
35
  });
36
36
  describe('attributes', () => {
37
37
  it('should preserve attributes on void elements', () => {
38
38
  const input = '<img src="test.png" alt="Test Image" width="100">';
39
39
  const output = convertHtmlToJsx(input);
40
- expect(output).toBe('<><img src="test.png" alt="Test Image" width="100"/></>');
40
+ expect(output).toBe('<><img src="test.png" alt="Test Image" width="100" /></>');
41
41
  });
42
42
  it('should preserve attributes on regular elements', () => {
43
43
  const input = '<div class="container" id="main">Content</div>';
@@ -59,7 +59,7 @@ describe('convertHtmlToJsx', () => {
59
59
  it('should handle void elements within nested structures', () => {
60
60
  const input = '<div><p>Line 1<br>Line 2</p><hr><p>Line 3</p></div>';
61
61
  const output = convertHtmlToJsx(input);
62
- expect(output).toBe('<><div><p>Line 1<br/>Line 2</p><hr/><p>Line 3</p></div></>');
62
+ expect(output).toBe('<><div><p>Line 1<br />Line 2</p><hr /><p>Line 3</p></div></>');
63
63
  });
64
64
  });
65
65
  describe('text content', () => {
@@ -100,8 +100,8 @@ describe('convertHtmlToJsx', () => {
100
100
  it('should handle empty elements', () => {
101
101
  const input = '<strong></strong>';
102
102
  const output = convertHtmlToJsx(input);
103
- // Empty elements are converted to self-closing tags in XHTML
104
- expect(output).toBe('<><strong/></>');
103
+ // Empty non-void elements remain as open/close tags (not self-closing)
104
+ expect(output).toBe('<><strong></strong></>');
105
105
  });
106
106
  it('should handle plain text without tags', () => {
107
107
  const input = 'Just plain text';
@@ -1,4 +1,4 @@
1
- import { ComponentName, ComponentPropDocumentation } from './types.ts';
1
+ import type { ComponentName, ComponentPropDocumentation } from './types.ts';
2
2
  /**
3
3
  * Gets the documentation for the props of a component.
4
4
  *
@@ -1,9 +1,9 @@
1
1
  import { isObjectNode, isTypeReferenceNode, } from '@hubspot/ts-export-types-reader';
2
2
  import { componentPropsReader } from "./__generated__/component-props.js";
3
- import { renderPropTypeToJsx, } from "./internal/render-prop-type.js";
4
- import { getDefaultValueFromJsdocTags, getSeeTagsFromJsdocTags, } from "./internal/utils/jsdoc-utils.js";
5
- import { renderMarkdownToJsx } from "./internal/utils/markdown-utils.js";
6
3
  import { getComponentTypeSource } from "./internal/get-type-source.js";
4
+ import { renderPropTypeToJsx } from "./internal/render-prop-type.js";
5
+ import { getDefaultValueFromJsdocTags, getSeeTagsFromJsdocTags, hasDeprecatedJsdocTag, } from "./internal/utils/jsdoc-utils.js";
6
+ import { renderMarkdownToJsx } from "./internal/utils/markdown-utils.js";
7
7
  /**
8
8
  * Recursively resolves an API node to an ObjectNode if possible.
9
9
  *
@@ -73,8 +73,10 @@ export const getComponentPropsDocumentation = (componentName) => {
73
73
  if (!propsObject) {
74
74
  throw new Error(`Props object not found for component "${componentName}" (${exportName} in ${exportPath})`);
75
75
  }
76
- // Sort properties first by required status, then alphabetically by name for consistent output
77
- const props = [...propsObject.properties].sort((a, b) => {
76
+ // Filter out deprecated properties, then sort by required status and alphabetically by name for consistent output
77
+ const props = [...propsObject.properties]
78
+ .filter((prop) => !hasDeprecatedJsdocTag(prop.jsdoc?.tags))
79
+ .sort((a, b) => {
78
80
  const aRequired = a.isOptional !== true;
79
81
  const bRequired = b.isOptional !== true;
80
82
  if (aRequired !== bRequired) {
@@ -1,4 +1,4 @@
1
- import { ComponentName } from '../types.ts';
1
+ import type { ComponentName } from '../types.ts';
2
2
  export interface ComponentSource {
3
3
  exportName: string;
4
4
  exportPath: string;
@@ -284,6 +284,10 @@ const componentSourceLookup = {
284
284
  exportName: 'SettingsViewProps',
285
285
  exportPath: './experimental',
286
286
  },
287
+ Spacer: {
288
+ exportName: 'SpacerProps',
289
+ exportPath: '.',
290
+ },
287
291
  Stack2: {
288
292
  exportName: 'Stack2Props',
289
293
  exportPath: './experimental',
@@ -1,4 +1,4 @@
1
- import { AnalyzeResultReader, ApiNode } from '@hubspot/ts-export-types-reader';
1
+ import type { AnalyzeResultReader, ApiNode } from '@hubspot/ts-export-types-reader';
2
2
  /**
3
3
  * Context object passed through the type rendering functions.
4
4
  *
@@ -4,7 +4,7 @@
4
4
  * This module provides helper functions for parsing and extracting information
5
5
  * from JSDoc comments associated with component props, such as default values.
6
6
  */
7
- import { JsdocTag } from '@hubspot/ts-export-types-reader';
7
+ import type { JsdocTag } from '@hubspot/ts-export-types-reader';
8
8
  /**
9
9
  * Extracts the default value from JSDoc tags.
10
10
  *
@@ -27,3 +27,14 @@ export declare const getDefaultValueFromJsdocTags: (tags: JsdocTag[] | undefined
27
27
  * @returns An array of see tag text values, or an empty array if none found
28
28
  */
29
29
  export declare const getSeeTagsFromJsdocTags: (tags: JsdocTag[] | undefined) => string[];
30
+ /**
31
+ * Checks if a property is deprecated based on JSDoc tags.
32
+ *
33
+ * Searches through an array of JSDoc tags to determine if a 'deprecated'
34
+ * tag exists. Properties marked as deprecated should be filtered out from
35
+ * documentation.
36
+ *
37
+ * @param tags - An array of JSDoc tags, or undefined if no tags exist
38
+ * @returns True if a deprecated tag is found, false otherwise
39
+ */
40
+ export declare const hasDeprecatedJsdocTag: (tags: JsdocTag[] | undefined) => boolean;
@@ -50,3 +50,21 @@ export const getSeeTagsFromJsdocTags = (tags) => {
50
50
  .filter((tag) => tag.name === 'see' && tag.text)
51
51
  .map((tag) => tag.text);
52
52
  };
53
+ /**
54
+ * Checks if a property is deprecated based on JSDoc tags.
55
+ *
56
+ * Searches through an array of JSDoc tags to determine if a 'deprecated'
57
+ * tag exists. Properties marked as deprecated should be filtered out from
58
+ * documentation.
59
+ *
60
+ * @param tags - An array of JSDoc tags, or undefined if no tags exist
61
+ * @returns True if a deprecated tag is found, false otherwise
62
+ */
63
+ export const hasDeprecatedJsdocTag = (tags) => {
64
+ // Return false if there are no tags
65
+ if (!tags) {
66
+ return false;
67
+ }
68
+ // Check if any tag is named 'deprecated'
69
+ return tags.some((tag) => tag.name === 'deprecated');
70
+ };
@@ -1,5 +1,5 @@
1
- import { parseDocument, DomUtils } from 'htmlparser2';
2
1
  import serialize from 'dom-serializer';
2
+ import { DomUtils, parseDocument } from 'htmlparser2';
3
3
  const escapeJsxExpressions = (jsx) => {
4
4
  return jsx.replaceAll('{', '&#123;').replaceAll('}', '&#125;');
5
5
  };
@@ -70,8 +70,18 @@ export const convertHtmlToJsx = (html) => {
70
70
  stripOutermostParagraphNode(dom);
71
71
  // Serialize back to string with XML rules (self-closing tags, etc.)
72
72
  const xhtml = serialize(dom, {
73
- xmlMode: true, // Use XML/XHTML serialization rules
74
- selfClosingTags: true, // Ensure void elements are self-closing
73
+ // xmlMode defaults to true which is more aggressive and unnecessary encoding of element text so we turn it off.
74
+ // We still output XHTML (well-formed XML) by enabling emptyAttrs and selfClosingTags.
75
+ xmlMode: false,
76
+ // Print empty attribute values as attr="" (e.g., <input checked=""/>)
77
+ emptyAttrs: true,
78
+ // Self-close HTML void elements (br, img, etc.) as <br /> for JSX compatibility.
79
+ // Note: Non-void empty elements render as <span></span> (not <span/>), but this is fine for JSX.
80
+ selfClosingTags: true,
81
+ // encodeEntities controls how element text is encoded. We use utf8 to ensure all
82
+ // special characters are encoded in addition to the characters that are already encoded by default (&, <, >)
83
+ // but results in quotes not being encoded for better readability.
84
+ encodeEntities: 'utf8',
75
85
  });
76
86
  return `<>${escapeJsxExpressions(xhtml)}</>`;
77
87
  };
package/dist/types.d.ts CHANGED
@@ -105,6 +105,7 @@ export declare enum ComponentName {
105
105
  SecondaryHeaderActionButton = "SecondaryHeaderActionButton",
106
106
  Select = "Select",
107
107
  SettingsView = "SettingsView",
108
+ Spacer = "Spacer",
108
109
  Stack2 = "Stack2",
109
110
  Statistics = "Statistics",
110
111
  StatisticsItem = "StatisticsItem",
package/dist/types.js CHANGED
@@ -75,6 +75,7 @@ export var ComponentName;
75
75
  ComponentName["SecondaryHeaderActionButton"] = "SecondaryHeaderActionButton";
76
76
  ComponentName["Select"] = "Select";
77
77
  ComponentName["SettingsView"] = "SettingsView";
78
+ ComponentName["Spacer"] = "Spacer";
78
79
  ComponentName["Stack2"] = "Stack2";
79
80
  ComponentName["Statistics"] = "Statistics";
80
81
  ComponentName["StatisticsItem"] = "StatisticsItem";
package/package.json CHANGED
@@ -1,19 +1,9 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions-sdk-api-metadata",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "UI Extensions SDK API Metadata",
5
5
  "type": "module",
6
- "scripts": {
7
- "clean": "rm -rf dist/ src/__generated__/",
8
- "build": "npm run clean && npm run generate && tsc",
9
- "check:tsc": "tsc",
10
- "generate": "npm run generate:sdk-api-metadata",
11
- "generate:sdk-api-metadata": "(cd ../ui-extensions-components && npm run build) && ts-export-types analyze --config ts-export-types.component-props.config.js",
12
- "test": "vitest run",
13
- "watch": "npm run clean && tsc --watch",
14
- "prepublishOnly": "npm run build",
15
- "lint": "echo 'No linter configured for @hubspot/ui-extensions-sdk-api-metadata'"
16
- },
6
+ "prettier": "@private/prettier-config",
17
7
  "files": [
18
8
  "dist"
19
9
  ],
@@ -26,17 +16,36 @@
26
16
  "license": "MIT",
27
17
  "dependencies": {
28
18
  "@hubspot/ts-export-types-reader": "1.1.0",
29
- "dom-serializer": "^2.0.0",
30
- "htmlparser2": "^9.1.0",
19
+ "dom-serializer": "2.0.0",
20
+ "htmlparser2": "9.1.0",
31
21
  "marked": "17.0.1"
32
22
  },
33
23
  "devDependencies": {
34
24
  "@hubspot/ts-export-types": "1.1.0",
35
- "@vitest/coverage-v8": "2.1.8",
25
+ "@types/node": "22.19.7",
26
+ "@vitest/coverage-v8": "4.0.18",
27
+ "@vitest/eslint-plugin": "1.6.6",
28
+ "eslint": "9.39.2",
29
+ "prettier": "3.8.1",
36
30
  "typescript": "5.9.3",
37
- "vitest": "2.1.9"
31
+ "vitest": "4.0.18",
32
+ "@private/eslint-config": "1.0.0",
33
+ "@private/prettier-config": "1.0.0",
34
+ "@hubspot/ui-extensions": "0.12.3"
38
35
  },
39
36
  "engines": {
40
37
  "node": ">=16"
38
+ },
39
+ "scripts": {
40
+ "clean": "rm -rf dist/ *.tsbuildinfo .turbo src/__generated__/",
41
+ "format": "prettier --write . --ignore-path ../../.prettierignore",
42
+ "format:check": "prettier --check . --ignore-path ../../.prettierignore",
43
+ "generate": "pnpm run generate:sdk-api-metadata",
44
+ "generate:sdk-api-metadata": "ts-export-types analyze --config ts-export-types.component-props.config.js",
45
+ "lint": "eslint src/",
46
+ "lint:fix": "eslint src/ --fix",
47
+ "test": "vitest run",
48
+ "tsc": "tsc",
49
+ "tsc:watch": "tsc --watch"
41
50
  }
42
- }
51
+ }