@hubspot/eslint-config-ui-extensions 0.12.0 → 1.1.0

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 (78) hide show
  1. package/README.md +168 -24
  2. package/dist/__tests__/index.spec.d.ts +1 -0
  3. package/dist/__tests__/index.spec.js +303 -0
  4. package/dist/__tests__/rules/no-browser-dialogs.spec.d.ts +1 -0
  5. package/dist/__tests__/rules/no-browser-dialogs.spec.js +263 -0
  6. package/dist/__tests__/rules/no-browser-storage.spec.d.ts +1 -0
  7. package/dist/__tests__/rules/no-browser-storage.spec.js +428 -0
  8. package/dist/__tests__/rules/no-console.spec.d.ts +1 -0
  9. package/dist/__tests__/rules/no-console.spec.js +262 -0
  10. package/dist/__tests__/rules/no-dom-access.spec.d.ts +1 -0
  11. package/dist/__tests__/rules/no-dom-access.spec.js +288 -0
  12. package/dist/__tests__/rules/no-experimental-imports.spec.d.ts +1 -0
  13. package/dist/__tests__/rules/no-experimental-imports.spec.js +67 -0
  14. package/dist/__tests__/rules/no-html-elements.spec.d.ts +1 -0
  15. package/dist/__tests__/rules/no-html-elements.spec.js +142 -0
  16. package/dist/__tests__/rules/no-invalid-extension-point-imports.spec.d.ts +1 -0
  17. package/dist/__tests__/rules/no-invalid-extension-point-imports.spec.js +269 -0
  18. package/dist/__tests__/rules/no-invalid-image-src.spec.d.ts +1 -0
  19. package/dist/__tests__/rules/no-invalid-image-src.spec.js +227 -0
  20. package/dist/__tests__/rules/no-native-http.spec.d.ts +1 -0
  21. package/dist/__tests__/rules/no-native-http.spec.js +596 -0
  22. package/dist/__tests__/rules/no-parent-imports.spec.d.ts +1 -0
  23. package/dist/__tests__/rules/no-parent-imports.spec.js +337 -0
  24. package/dist/__tests__/rules/no-restricted-globals.spec.d.ts +1 -0
  25. package/dist/__tests__/rules/no-restricted-globals.spec.js +434 -0
  26. package/dist/__tests__/utils/ast-utils.spec.d.ts +1 -0
  27. package/dist/__tests__/utils/ast-utils.spec.js +297 -0
  28. package/dist/__tests__/utils/extension-point-utils.spec.d.ts +1 -0
  29. package/dist/__tests__/utils/extension-point-utils.spec.js +125 -0
  30. package/dist/__tests__/utils/import-utils.spec.d.ts +1 -0
  31. package/dist/__tests__/utils/import-utils.spec.js +176 -0
  32. package/dist/__tests__/utils/jsx-utils.spec.d.ts +1 -0
  33. package/dist/__tests__/utils/jsx-utils.spec.js +120 -0
  34. package/dist/__tests__/utils/scope-utils.spec.d.ts +1 -0
  35. package/dist/__tests__/utils/scope-utils.spec.js +80 -0
  36. package/dist/constants.d.ts +3 -0
  37. package/dist/constants.js +124 -0
  38. package/dist/index.d.ts +4 -0
  39. package/dist/index.js +75 -0
  40. package/dist/rules/no-browser-dialogs.d.ts +2 -0
  41. package/dist/rules/no-browser-dialogs.js +62 -0
  42. package/dist/rules/no-browser-storage.d.ts +2 -0
  43. package/dist/rules/no-browser-storage.js +78 -0
  44. package/dist/rules/no-console.d.ts +2 -0
  45. package/dist/rules/no-console.js +78 -0
  46. package/dist/rules/no-dom-access.d.ts +2 -0
  47. package/dist/rules/no-dom-access.js +63 -0
  48. package/dist/rules/no-experimental-imports.d.ts +2 -0
  49. package/dist/rules/no-experimental-imports.js +29 -0
  50. package/dist/rules/no-html-elements.d.ts +2 -0
  51. package/dist/rules/no-html-elements.js +39 -0
  52. package/dist/rules/no-invalid-extension-point-imports.d.ts +2 -0
  53. package/dist/rules/no-invalid-extension-point-imports.js +54 -0
  54. package/dist/rules/no-invalid-image-src.d.ts +2 -0
  55. package/dist/rules/no-invalid-image-src.js +120 -0
  56. package/dist/rules/no-native-http.d.ts +2 -0
  57. package/dist/rules/no-native-http.js +70 -0
  58. package/dist/rules/no-parent-imports.d.ts +2 -0
  59. package/dist/rules/no-parent-imports.js +46 -0
  60. package/dist/rules/no-restricted-globals.d.ts +2 -0
  61. package/dist/rules/no-restricted-globals.js +132 -0
  62. package/dist/runtime.d.ts +2 -0
  63. package/dist/runtime.js +13 -0
  64. package/dist/utils/ast-utils.d.ts +42 -0
  65. package/dist/utils/ast-utils.js +79 -0
  66. package/dist/utils/extension-point-utils.d.ts +57 -0
  67. package/dist/utils/extension-point-utils.js +108 -0
  68. package/dist/utils/import-utils.d.ts +34 -0
  69. package/dist/utils/import-utils.js +52 -0
  70. package/dist/utils/jsx-utils.d.ts +30 -0
  71. package/dist/utils/jsx-utils.js +40 -0
  72. package/dist/utils/scope-utils.d.ts +30 -0
  73. package/dist/utils/scope-utils.js +66 -0
  74. package/package.json +43 -24
  75. package/CHANGELOG.md +0 -51
  76. package/eslintrc.js +0 -12
  77. package/lib/index.js +0 -57
  78. package/lib/runtime.js +0 -17
@@ -0,0 +1,142 @@
1
+ import { RuleTester } from 'eslint';
2
+ import { unsupportedHtmlElements } from "../../rules/no-html-elements.js";
3
+ import { languageOptions } from "../../runtime.js";
4
+ const ruleTester = new RuleTester({
5
+ languageOptions: {
6
+ ...languageOptions,
7
+ parserOptions: {
8
+ ecmaFeatures: {
9
+ jsx: true,
10
+ },
11
+ },
12
+ },
13
+ });
14
+ const simpleValidElement = `
15
+ function App() {
16
+ return <Button>Click Me</Button>
17
+ };
18
+ `;
19
+ const nestedValidElements = `
20
+ function App() {
21
+ return (
22
+ <Box>
23
+ <Text>A Headline</Text>
24
+ <Button>Click Me</Button>
25
+ </Box>
26
+ );
27
+ };
28
+ `;
29
+ const reactFragmentValidElements = `
30
+ function App() {
31
+ return (
32
+ <>
33
+ <Text>Fragment Text</Text>
34
+ <Button>Click Me</Button>
35
+ </>
36
+ );
37
+ };
38
+ `;
39
+ const customDivValidElement = `
40
+ function Div() {
41
+ return <Box>Custom Div</Box>
42
+ };
43
+
44
+ function App() {
45
+ return <Div />;
46
+ };
47
+ `;
48
+ const simpleInvalidElement = `
49
+ function App() {
50
+ return <div>Invalid Element</div>;
51
+ };
52
+ `;
53
+ const nestedInvalidElements = `
54
+ function App() {
55
+ return (
56
+ <div>
57
+ <h1>Invalid Header</h1>
58
+ <p>Invalid paragraph content <a href="#">with a link</a> and a <span style="font-weight: bold;">span tag for extra styling.</span></p>
59
+ <button>Click Me</button>
60
+ </div>
61
+ );
62
+ };
63
+ `;
64
+ const selfClosingInvalidElement = `
65
+ function App() {
66
+ return <img src="image.png" alt="Invalid Image" />;
67
+ };
68
+ `;
69
+ describe('no-html-elements', () => {
70
+ ruleTester.run('no-html-elements', unsupportedHtmlElements, {
71
+ valid: [
72
+ {
73
+ name: 'allows simple valid UI Extension components',
74
+ code: simpleValidElement,
75
+ },
76
+ {
77
+ name: 'allows nested valid UI Extension components',
78
+ code: nestedValidElements,
79
+ },
80
+ {
81
+ name: 'allows React Fragment syntax',
82
+ code: reactFragmentValidElements,
83
+ },
84
+ {
85
+ name: 'allows PascalCase component names that match HTML element names',
86
+ code: customDivValidElement,
87
+ },
88
+ ],
89
+ invalid: [
90
+ {
91
+ name: 'reports error for simple HTML element',
92
+ code: simpleInvalidElement,
93
+ errors: [
94
+ {
95
+ messageId: 'htmlNotSupported',
96
+ data: { elementName: 'div' },
97
+ },
98
+ ],
99
+ },
100
+ {
101
+ name: 'reports errors for multiple nested HTML elements',
102
+ code: nestedInvalidElements,
103
+ errors: [
104
+ {
105
+ messageId: 'htmlNotSupported',
106
+ data: { elementName: 'div' },
107
+ },
108
+ {
109
+ messageId: 'htmlNotSupported',
110
+ data: { elementName: 'h1' },
111
+ },
112
+ {
113
+ messageId: 'htmlNotSupported',
114
+ data: { elementName: 'p' },
115
+ },
116
+ {
117
+ messageId: 'htmlNotSupported',
118
+ data: { elementName: 'a' },
119
+ },
120
+ {
121
+ messageId: 'htmlNotSupported',
122
+ data: { elementName: 'span' },
123
+ },
124
+ {
125
+ messageId: 'htmlNotSupported',
126
+ data: { elementName: 'button' },
127
+ },
128
+ ],
129
+ },
130
+ {
131
+ name: 'reports error for self-closing HTML elements',
132
+ code: selfClosingInvalidElement,
133
+ errors: [
134
+ {
135
+ messageId: 'htmlNotSupported',
136
+ data: { elementName: 'img' },
137
+ },
138
+ ],
139
+ },
140
+ ],
141
+ });
142
+ });
@@ -0,0 +1,269 @@
1
+ import { RuleTester } from 'eslint';
2
+ import { noInvalidExtensionPointImports } from "../../rules/no-invalid-extension-point-imports.js";
3
+ import { languageOptions } from "../../runtime.js";
4
+ const ruleTesterOptions = {
5
+ languageOptions: {
6
+ ...languageOptions,
7
+ parserOptions: {
8
+ ecmaFeatures: {
9
+ jsx: true,
10
+ },
11
+ },
12
+ },
13
+ };
14
+ const basicImport = `
15
+ import { hubspot } from '@hubspot/ui-extensions';
16
+ `;
17
+ const crmImport = `
18
+ import { useCrmProperties } from '@hubspot/ui-extensions/crm/hooks';
19
+ `;
20
+ const settingsImport = `
21
+ import { SettingsComponent } from '@hubspot/ui-extensions/settings';
22
+ `;
23
+ const pagesImport = `
24
+ import { PageComponent } from '@hubspot/ui-extensions/pages';
25
+ `;
26
+ const hookImport = `
27
+ import { useExtensionContext } from '@hubspot/ui-extensions/hooks';
28
+ `;
29
+ const externalImport = `
30
+ import { useEffect } from 'react';
31
+ import { FakeComponent } from 'apackage/extensions/pages';
32
+ `;
33
+ describe('no-invalid-extension-point-imports', () => {
34
+ describe('in cards directory', () => {
35
+ const ruleTester = new RuleTester(ruleTesterOptions);
36
+ ruleTester.run('no-invalid-extension-point-imports', noInvalidExtensionPointImports, {
37
+ valid: [
38
+ {
39
+ name: 'basic UI Extensions import',
40
+ code: basicImport,
41
+ filename: '/path/to/project/src/app/cards/Component.tsx',
42
+ },
43
+ {
44
+ name: 'CRM import',
45
+ code: crmImport,
46
+ filename: '/path/to/project/src/app/cards/Component.tsx',
47
+ },
48
+ {
49
+ name: 'hooks import',
50
+ code: hookImport,
51
+ filename: '/path/to/project/src/app/cards/Component.tsx',
52
+ },
53
+ {
54
+ name: 'external library import',
55
+ code: externalImport,
56
+ filename: '/path/to/project/src/app/cards/Component.tsx',
57
+ },
58
+ ],
59
+ invalid: [
60
+ {
61
+ name: 'settings import',
62
+ code: settingsImport,
63
+ filename: '/path/to/project/src/app/cards/Component.tsx',
64
+ errors: [
65
+ {
66
+ message: 'Imports from "settings" are not allowed in cards.',
67
+ },
68
+ ],
69
+ },
70
+ {
71
+ name: 'pages import',
72
+ code: pagesImport,
73
+ filename: '/path/to/project/src/app/cards/Component.tsx',
74
+ errors: [
75
+ {
76
+ message: 'Imports from "pages" are not allowed in cards.',
77
+ },
78
+ ],
79
+ },
80
+ ],
81
+ });
82
+ });
83
+ describe('in extensions directory', () => {
84
+ const ruleTester = new RuleTester(ruleTesterOptions);
85
+ ruleTester.run('no-invalid-extension-point-imports', noInvalidExtensionPointImports, {
86
+ valid: [
87
+ {
88
+ name: 'basic UI Extensions import',
89
+ code: basicImport,
90
+ filename: '/path/to/project/src/app/extensions/Component.tsx',
91
+ },
92
+ {
93
+ name: 'CRM import',
94
+ code: crmImport,
95
+ filename: '/path/to/project/src/app/extensions/Component.tsx',
96
+ },
97
+ {
98
+ name: 'hooks import',
99
+ code: hookImport,
100
+ filename: '/path/to/project/src/app/extensions/Component.tsx',
101
+ },
102
+ {
103
+ name: 'external library import',
104
+ code: externalImport,
105
+ filename: '/path/to/project/src/app/extensions/Component.tsx',
106
+ },
107
+ ],
108
+ invalid: [
109
+ {
110
+ name: 'settings import',
111
+ code: settingsImport,
112
+ filename: '/path/to/project/src/app/extensions/Component.tsx',
113
+ errors: [
114
+ {
115
+ message: 'Imports from "settings" are not allowed in extensions.',
116
+ },
117
+ ],
118
+ },
119
+ {
120
+ name: 'pages import',
121
+ code: pagesImport,
122
+ filename: '/path/to/project/src/app/extensions/Component.tsx',
123
+ errors: [
124
+ {
125
+ message: 'Imports from "pages" are not allowed in extensions.',
126
+ },
127
+ ],
128
+ },
129
+ ],
130
+ });
131
+ });
132
+ describe('in settings directory', () => {
133
+ const ruleTester = new RuleTester(ruleTesterOptions);
134
+ ruleTester.run('no-invalid-extension-point-imports', noInvalidExtensionPointImports, {
135
+ valid: [
136
+ {
137
+ name: 'basic UI Extensions import',
138
+ code: basicImport,
139
+ filename: '/path/to/project/src/app/settings/Component.tsx',
140
+ },
141
+ {
142
+ name: 'settings import',
143
+ code: settingsImport,
144
+ filename: '/path/to/project/src/app/settings/Component.tsx',
145
+ },
146
+ {
147
+ name: 'hooks import',
148
+ code: hookImport,
149
+ filename: '/path/to/project/src/app/settings/Component.tsx',
150
+ },
151
+ {
152
+ name: 'external library import',
153
+ code: externalImport,
154
+ filename: '/path/to/project/src/app/settings/Component.tsx',
155
+ },
156
+ ],
157
+ invalid: [
158
+ {
159
+ name: 'CRM import',
160
+ code: crmImport,
161
+ filename: '/path/to/project/src/app/settings/Component.tsx',
162
+ errors: [
163
+ {
164
+ message: 'Imports from "crm" are not allowed in settings.',
165
+ },
166
+ ],
167
+ },
168
+ {
169
+ name: 'pages import',
170
+ code: pagesImport,
171
+ filename: '/path/to/project/src/app/settings/Component.tsx',
172
+ errors: [
173
+ {
174
+ message: 'Imports from "pages" are not allowed in settings.',
175
+ },
176
+ ],
177
+ },
178
+ ],
179
+ });
180
+ });
181
+ describe('in pages directory', () => {
182
+ const ruleTester = new RuleTester(ruleTesterOptions);
183
+ ruleTester.run('no-invalid-extension-point-imports', noInvalidExtensionPointImports, {
184
+ valid: [
185
+ {
186
+ name: 'basic UI Extensions import',
187
+ code: basicImport,
188
+ filename: '/path/to/project/src/app/pages/Component.tsx',
189
+ },
190
+ {
191
+ name: 'pages import',
192
+ code: pagesImport,
193
+ filename: '/path/to/project/src/app/pages/Component.tsx',
194
+ },
195
+ {
196
+ name: 'hooks import',
197
+ code: hookImport,
198
+ filename: '/path/to/project/src/app/pages/Component.tsx',
199
+ },
200
+ {
201
+ name: 'external library import',
202
+ code: externalImport,
203
+ filename: '/path/to/project/src/app/pages/Component.tsx',
204
+ },
205
+ ],
206
+ invalid: [
207
+ {
208
+ name: 'CRM import',
209
+ code: crmImport,
210
+ filename: '/path/to/project/src/app/pages/Component.tsx',
211
+ errors: [
212
+ {
213
+ message: 'Imports from "crm" are not allowed in pages.',
214
+ },
215
+ ],
216
+ },
217
+ {
218
+ name: 'settings import',
219
+ code: settingsImport,
220
+ filename: '/path/to/project/src/app/pages/Component.tsx',
221
+ errors: [
222
+ {
223
+ message: 'Imports from "settings" are not allowed in pages.',
224
+ },
225
+ ],
226
+ },
227
+ ],
228
+ });
229
+ });
230
+ describe('in nested folders', () => {
231
+ const ruleTester = new RuleTester(ruleTesterOptions);
232
+ ruleTester.run('no-invalid-extension-point-imports', noInvalidExtensionPointImports, {
233
+ valid: [
234
+ {
235
+ name: 'pages import',
236
+ code: pagesImport,
237
+ filename: '/path/to/project/src/app/pages/nested/Component.tsx',
238
+ },
239
+ {
240
+ name: 'CRM import in nested pages directory',
241
+ code: crmImport,
242
+ filename: '/path/to/project/src/app/cards/pages/Component.tsx',
243
+ },
244
+ ],
245
+ invalid: [
246
+ {
247
+ name: 'CRM import',
248
+ code: crmImport,
249
+ filename: '/path/to/project/src/app/pages/nested/Component.tsx',
250
+ errors: [
251
+ {
252
+ message: 'Imports from "crm" are not allowed in pages.',
253
+ },
254
+ ],
255
+ },
256
+ {
257
+ name: 'Pages import in nested pages directory',
258
+ code: pagesImport,
259
+ filename: '/path/to/project/src/app/cards/pages/Component.tsx',
260
+ errors: [
261
+ {
262
+ message: 'Imports from "pages" are not allowed in cards.',
263
+ },
264
+ ],
265
+ },
266
+ ],
267
+ });
268
+ });
269
+ });
@@ -0,0 +1,227 @@
1
+ import { RuleTester } from 'eslint';
2
+ import { noInvalidImageSrc } from "../../rules/no-invalid-image-src.js";
3
+ import { languageOptions } from "../../runtime.js";
4
+ const ruleTester = new RuleTester({
5
+ languageOptions: {
6
+ ...languageOptions,
7
+ parserOptions: {
8
+ ecmaFeatures: {
9
+ jsx: true,
10
+ },
11
+ },
12
+ },
13
+ });
14
+ describe('no-invalid-image-src', () => {
15
+ ruleTester.run('no-invalid-image-src', noInvalidImageSrc, {
16
+ valid: [
17
+ {
18
+ name: 'allows valid https URL',
19
+ code: `
20
+ import { Image } from '@hubspot/ui-extensions';
21
+ function App() {
22
+ return <Image src="https://example.com/image.png" />;
23
+ }
24
+ `,
25
+ },
26
+ {
27
+ name: 'allows valid http URL',
28
+ code: `
29
+ import { Image } from '@hubspot/ui-extensions';
30
+ function App() {
31
+ return <Image src="http://localhost:3000/image.jpg" />;
32
+ }
33
+ `,
34
+ },
35
+ {
36
+ name: 'allows data URL with base64 PNG',
37
+ code: `
38
+ import { Image } from '@hubspot/ui-extensions';
39
+ function App() {
40
+ return <Image src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" />;
41
+ }
42
+ `,
43
+ },
44
+ {
45
+ name: 'allows data URL with SVG',
46
+ code: `
47
+ import { Image } from '@hubspot/ui-extensions';
48
+ function App() {
49
+ return <Image src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3Ccircle cx='50' cy='50' r='40' fill='%23007bff'/%3E%3C/svg%3E" />;
50
+ }
51
+ `,
52
+ },
53
+ {
54
+ name: 'allows URL with query string and fragment',
55
+ code: `
56
+ import { Image } from '@hubspot/ui-extensions';
57
+ function App() {
58
+ return <Image src="https://example.com/image.webp?v=2#top" />;
59
+ }
60
+ `,
61
+ },
62
+ {
63
+ name: 'allows imported image module as src',
64
+ code: `
65
+ import { Image } from '@hubspot/ui-extensions';
66
+ import testImage from './testImage.png';
67
+ function App() {
68
+ return <Image src={testImage} />;
69
+ }
70
+ `,
71
+ },
72
+ {
73
+ name: 'allows all image types',
74
+ code: `
75
+ import { Image } from '@hubspot/ui-extensions';
76
+ function App() {
77
+ return (
78
+ <>
79
+ <Image src="https://example.com/photo.jpg" />
80
+ <Image src="https://example.com/photo.jpeg" />
81
+ <Image src="https://example.com/photo.png" />
82
+ <Image src="https://example.com/photo.gif" />
83
+ <Image src="https://example.com/photo.svg" />
84
+ <Image src="https://example.com/photo.webp" />
85
+ </>
86
+ );
87
+ }
88
+ `,
89
+ },
90
+ {
91
+ name: 'allows aliased Image import',
92
+ code: `
93
+ import { Image as HubImage } from '@hubspot/ui-extensions';
94
+ function App() {
95
+ return <HubImage src="https://example.com/image.png" />;
96
+ }
97
+ `,
98
+ },
99
+ {
100
+ name: 'ignores Image component when not imported from @hubspot/ui-extensions',
101
+ code: `
102
+ import { Text } from '@hubspot/ui-extensions';
103
+ function App() {
104
+ return <Image src="./relative.png" />;
105
+ }
106
+ `,
107
+ },
108
+ {
109
+ name: 'ignores src attributes on other components',
110
+ code: `
111
+ import { Iframe } from '@hubspot/ui-extensions';
112
+ function App() {
113
+ return <Iframe src="https://somesite.com" />;
114
+ }
115
+ `,
116
+ },
117
+ ],
118
+ invalid: [
119
+ {
120
+ name: 'reports error for relative path with ./',
121
+ code: `
122
+ import { Image } from '@hubspot/ui-extensions';
123
+ function App() {
124
+ return <Image src="./image.png" />;
125
+ }
126
+ `,
127
+ errors: [{ messageId: 'invalidRelativeUrl' }],
128
+ },
129
+ {
130
+ name: 'reports error for relative path with ../',
131
+ code: `
132
+ import { Image } from '@hubspot/ui-extensions';
133
+ function App() {
134
+ return <Image src="../images/logo.svg" />;
135
+ }
136
+ `,
137
+ errors: [{ messageId: 'invalidRelativeUrl' }],
138
+ },
139
+ {
140
+ name: 'reports error for absolute path',
141
+ code: `
142
+ import { Image } from '@hubspot/ui-extensions';
143
+ function App() {
144
+ return <Image src="/assets/image.png" />;
145
+ }
146
+ `,
147
+ errors: [{ messageId: 'invalidRelativeUrl' }],
148
+ },
149
+ {
150
+ name: 'reports error and fixes whitespace',
151
+ code: `
152
+ import { Image } from '@hubspot/ui-extensions';
153
+ function App() {
154
+ return <Image src=" https://example.com/image.png " />;
155
+ }
156
+ `,
157
+ output: `
158
+ import { Image } from '@hubspot/ui-extensions';
159
+ function App() {
160
+ return <Image src="https://example.com/image.png" />;
161
+ }
162
+ `,
163
+ errors: [{ messageId: 'whitespaceInUrl' }],
164
+ },
165
+ {
166
+ name: 'reports error for empty string',
167
+ code: `
168
+ import { Image } from '@hubspot/ui-extensions';
169
+ function App() {
170
+ return <Image src="" />;
171
+ }
172
+ `,
173
+ errors: [{ messageId: 'invalidRelativeUrl' }],
174
+ },
175
+ {
176
+ name: 'reports error for ftp:// protocol',
177
+ code: `
178
+ import { Image } from '@hubspot/ui-extensions';
179
+ function App() {
180
+ return <Image src="ftp://example.com/image.png" />;
181
+ }
182
+ `,
183
+ errors: [{ messageId: 'invalidProtocol' }],
184
+ },
185
+ {
186
+ name: 'reports error for file:// protocol',
187
+ code: `
188
+ import { Image } from '@hubspot/ui-extensions';
189
+ function App() {
190
+ return <Image src="file:///Users/me/image.png" />;
191
+ }
192
+ `,
193
+ errors: [{ messageId: 'invalidProtocol' }],
194
+ },
195
+ {
196
+ name: 'reports error for .pdf extension',
197
+ code: `
198
+ import { Image } from '@hubspot/ui-extensions';
199
+ function App() {
200
+ return <Image src="https://example.com/document.pdf" />;
201
+ }
202
+ `,
203
+ errors: [{ messageId: 'invalidImageType' }],
204
+ },
205
+ {
206
+ name: 'reports error for missing file extension',
207
+ code: `
208
+ import { Image } from '@hubspot/ui-extensions';
209
+ function App() {
210
+ return <Image src="https://example.com/image" />;
211
+ }
212
+ `,
213
+ errors: [{ messageId: 'invalidImageType' }],
214
+ },
215
+ {
216
+ name: 'reports error for aliased Image import with invalid src',
217
+ code: `
218
+ import { Image as HubImage } from '@hubspot/ui-extensions';
219
+ function App() {
220
+ return <HubImage src="/local/image.jpg" />;
221
+ }
222
+ `,
223
+ errors: [{ messageId: 'invalidRelativeUrl' }],
224
+ },
225
+ ],
226
+ });
227
+ });
@@ -0,0 +1 @@
1
+ export {};