@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.
- package/dist/__generated__/component-props.js +896 -360
- package/dist/__tests__/component-props-docs.spec.js +3 -0
- package/dist/__tests__/jsx-utils.spec.js +10 -10
- package/dist/component-props-docs.d.ts +1 -1
- package/dist/component-props-docs.js +7 -5
- package/dist/internal/get-type-source.d.ts +1 -1
- package/dist/internal/get-type-source.js +4 -0
- package/dist/internal/render-prop-type.d.ts +1 -1
- package/dist/internal/utils/jsdoc-utils.d.ts +12 -1
- package/dist/internal/utils/jsdoc-utils.js +18 -0
- package/dist/internal/utils/jsx-utils.js +13 -3
- package/dist/types.d.ts +1 -0
- package/dist/types.js +1 -0
- package/package.json +26 -17
|
@@ -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
|
|
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,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
|
-
//
|
|
77
|
-
const props = [...propsObject.properties]
|
|
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) {
|
|
@@ -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',
|
|
@@ -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('{', '{').replaceAll('}', '}');
|
|
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
|
|
74
|
-
|
|
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.
|
|
3
|
+
"version": "0.12.3",
|
|
4
4
|
"description": "UI Extensions SDK API Metadata",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"
|
|
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": "
|
|
30
|
-
"htmlparser2": "
|
|
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
|
-
"@
|
|
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": "
|
|
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
|
+
}
|