@octaviaflow/icon-build-helpers 1.0.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 (40) hide show
  1. package/README.md +50 -0
  2. package/package.json +55 -0
  3. package/src/builders/index.js +33 -0
  4. package/src/builders/plugins/virtual.js +51 -0
  5. package/src/builders/react/builder.js +313 -0
  6. package/src/builders/react/components/CarbonIcon.d.ts +18 -0
  7. package/src/builders/react/components/Icon.tsx +87 -0
  8. package/src/builders/react/next/babel.js +37 -0
  9. package/src/builders/react/next/convert.js +107 -0
  10. package/src/builders/react/next/templates.js +71 -0
  11. package/src/builders/react/next/typescript.js +87 -0
  12. package/src/builders/react/next.js +382 -0
  13. package/src/builders/svg.js +28 -0
  14. package/src/builders/vanilla.js +115 -0
  15. package/src/index.js +21 -0
  16. package/src/metadata/README.md +37 -0
  17. package/src/metadata/adapters/index.js +34 -0
  18. package/src/metadata/adapters/memory.js +55 -0
  19. package/src/metadata/adapters/yml.js +92 -0
  20. package/src/metadata/extension.js +92 -0
  21. package/src/metadata/extensions/assets.js +45 -0
  22. package/src/metadata/extensions/categories.js +141 -0
  23. package/src/metadata/extensions/deprecated.js +73 -0
  24. package/src/metadata/extensions/icons.js +152 -0
  25. package/src/metadata/extensions/index.js +48 -0
  26. package/src/metadata/extensions/module-info.js +154 -0
  27. package/src/metadata/extensions/module-name.js +54 -0
  28. package/src/metadata/extensions/output/getModuleName.js +52 -0
  29. package/src/metadata/extensions/output/index.js +251 -0
  30. package/src/metadata/extensions/output/optimizer.js +226 -0
  31. package/src/metadata/extensions/pictograms.js +85 -0
  32. package/src/metadata/index.js +178 -0
  33. package/src/metadata/migrations/2020-01-27.js +78 -0
  34. package/src/metadata/migrations/2020-02-17-remove-usage-fields.js +45 -0
  35. package/src/metadata/migrations/2020-02-17-update-pictogram-files.js +79 -0
  36. package/src/metadata/migrations/README.md +12 -0
  37. package/src/metadata/storage.js +68 -0
  38. package/src/metadata/validate.js +54 -0
  39. package/src/registry.js +158 -0
  40. package/src/tools.js +18 -0
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @octaviaflow/icon-build-helpers
2
+
3
+ > Build helpers for the Carbon Design System icon library
4
+
5
+ ## Getting started
6
+
7
+ To install `@octaviaflow/icon-build-helpers` in your project, you will need to run
8
+ the following command using [npm](https://www.npmjs.com/):
9
+
10
+ ```bash
11
+ npm install -S @octaviaflow/icon-build-helpers
12
+ ```
13
+
14
+ If you prefer [Yarn](https://yarnpkg.com/en/), use the following command
15
+ instead:
16
+
17
+ ```bash
18
+ yarn add @octaviaflow/icon-build-helpers
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ `@octaviaflow/icon-build-helpers` is a private module in the Carbon Design System
24
+ monorepo. The purpose of this module is to centralize tooling for:
25
+
26
+ - Searching a directory of `.svg` assets and structuring them in terms of size
27
+ and prefixes
28
+ - Custom builders for various libraries, which currently include:
29
+ - Vanilla
30
+ - React
31
+ - Implementing repo status checks in CI around icon metadata files, namely
32
+ `metadata.yml` and `categories.yml`
33
+
34
+ As a result, these file power the generation of the following SVG-based
35
+ projects:
36
+
37
+ - `@octaviaflow/icons`
38
+ - `@octaviaflow/icons-react`
39
+ - `@octaviaflow/pictograms`
40
+ - `@octaviaflow/pictograms-react`
41
+
42
+ ## 🙌 Contributing
43
+
44
+ We're always looking for contributors to help us fix bugs, build new features,
45
+ or help us improve the project documentation. If you're interested, definitely
46
+ check out our [Contributing Guide](/.github/CONTRIBUTING.md)! 👀
47
+
48
+ ## 📝 License
49
+
50
+ Licensed under the [Apache 2.0 License](/LICENSE).
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@octaviaflow/icon-build-helpers",
3
+ "description": "Build helpers for the OctaviaFlow Design System icon library",
4
+ "version": "1.0.0",
5
+ "license": "Apache-2.0",
6
+ "main": "src/index.js",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/octaviaflow-design-system.git",
10
+ "directory": "packages/icon-build-helpers"
11
+ },
12
+ "bugs": "https://github.com/octaviaflow-design-system/issues",
13
+ "keywords": [
14
+ "octaviaflow",
15
+ "icon-build-helpers",
16
+ "components",
17
+ "react"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "@babel/core": "^7.24.7",
24
+ "@babel/generator": "^7.24.7",
25
+ "@babel/preset-env": "^7.24.7",
26
+ "@babel/preset-react": "^7.24.7",
27
+ "@babel/template": "^7.24.7",
28
+ "@babel/types": "^7.24.7",
29
+ "@hapi/joi": "^17.1.1",
30
+ "@octaviaflow/cli-reporter": "^1.0.0",
31
+ "@octaviaflow/icon-helpers": "^1.0.0",
32
+ "@rollup/plugin-babel": "^6.0.0",
33
+ "@rollup/plugin-replace": "^6.0.0",
34
+ "browserslist-config-octaviaflow": "^1.0.0",
35
+ "change-case": "^4.1.1",
36
+ "core-js": "^3.16.0",
37
+ "fs-extra": "^11.0.0",
38
+ "js-yaml": "^3.12.1",
39
+ "klaw-sync": "^6.0.0",
40
+ "memfs": "^4.0.0",
41
+ "prettier": "^3.3.3",
42
+ "prop-types": "^15.6.2",
43
+ "react": "^19.2.0",
44
+ "react-dom": "^19.2.0",
45
+ "rimraf": "^6.0.0",
46
+ "rollup": "^2.79.1",
47
+ "rollup-plugin-strip-banner": "^3.0.0",
48
+ "svg-parser": "^2.0.4",
49
+ "svgo": "^1.1.1",
50
+ "svgson": "^5.2.1",
51
+ "typescript": "^5.9.3",
52
+ "typescript-config-octaviaflow": "^1.0.0"
53
+ },
54
+ "devDependencies": {}
55
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+
11
+ 'use strict';
12
+
13
+ const react = require('./react/builder');
14
+ const reactNext = require('./react/next');
15
+ const svg = require('./svg');
16
+ const vanilla = require('./vanilla');
17
+
18
+ const builders = {
19
+ react: {
20
+ run: react,
21
+ },
22
+ reactNext: {
23
+ run: reactNext,
24
+ },
25
+ svg: {
26
+ run: svg,
27
+ },
28
+ vanilla: {
29
+ run: vanilla,
30
+ },
31
+ };
32
+
33
+ module.exports = builders;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+
11
+ const path = require('path');
12
+
13
+ // Mirror of: https://github.com/rollup/rollup-plugin-virtual without the \0
14
+ // prefix which noops in a lot of plugins
15
+ const PREFIX = 'virtual:';
16
+
17
+ module.exports = function virtual(modules) {
18
+ const resolvedIds = new Map();
19
+
20
+ Object.keys(modules).forEach((id) => {
21
+ resolvedIds.set(path.resolve(id), modules[id]);
22
+ });
23
+
24
+ return {
25
+ name: 'virtual',
26
+
27
+ resolveId(id, importer) {
28
+ if (id in modules) {
29
+ return PREFIX + id;
30
+ }
31
+
32
+ if (importer) {
33
+ if (importer.startsWith(PREFIX)) {
34
+ importer = importer.slice(PREFIX.length);
35
+ }
36
+ const resolved = path.resolve(path.dirname(importer), id);
37
+ if (resolvedIds.has(resolved)) {
38
+ return PREFIX + resolved;
39
+ }
40
+ }
41
+ },
42
+
43
+ load(id) {
44
+ if (id.startsWith(PREFIX)) {
45
+ id = id.slice(PREFIX.length);
46
+
47
+ return id in modules ? modules[id] : resolvedIds.get(id);
48
+ }
49
+ },
50
+ };
51
+ };
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ "use strict";
11
+
12
+ const { babel } = require("@rollup/plugin-babel");
13
+ const { camelCase } = require("change-case");
14
+ const fs = require("fs-extra");
15
+ const path = require("path");
16
+ const { rollup } = require("rollup");
17
+ const virtual = require("../plugins/virtual");
18
+
19
+ const BANNER = `/**
20
+ * Copyright IBM Corp. 2019, 2023
21
+ *
22
+ * This source code is licensed under the Apache-2.0 license found in the
23
+ * LICENSE file in the root directory of this source tree.
24
+ *
25
+ * Code generated by @octaviaflow/icon-build-helpers. DO NOT EDIT.
26
+ */`;
27
+ const external = ["@octaviaflow/icon-helpers", "react", "prop-types"];
28
+ const babelConfig = {
29
+ babelrc: false,
30
+ exclude: /node_modules/,
31
+ presets: [
32
+ [
33
+ "@babel/preset-env",
34
+ {
35
+ targets: {
36
+ browsers: ["extends browserslist-config-octaviaflow"],
37
+ },
38
+ },
39
+ ],
40
+ "@babel/preset-react",
41
+ "@babel/preset-typescript",
42
+ ],
43
+ plugins: [
44
+ "@babel/plugin-transform-react-constant-elements",
45
+ "babel-plugin-dev-expression",
46
+ ],
47
+ babelHelpers: "bundled",
48
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
49
+ };
50
+
51
+ async function builder(metadata, { output }) {
52
+ // Using the metadata, we can build up a list of modules that we want included
53
+ // in the different bundles we ship.
54
+ //
55
+ // For each module, we need to create two ways of consuming it. The first way
56
+ // is as a dedicated module, the second as a single function that we could
57
+ // export in an entrypoint.
58
+ const modules = metadata.icons.flatMap((icon) => {
59
+ return icon.output.map((size) => {
60
+ return {
61
+ source: createIconFlatExport(
62
+ size.moduleName,
63
+ size.descriptor,
64
+ icon.deprecated,
65
+ ),
66
+ entrypoint: createIconEntrypoint(
67
+ size.moduleName,
68
+ size.descriptor,
69
+ icon.deprecated,
70
+ ),
71
+ filepath: size.filepath,
72
+ moduleName: size.moduleName,
73
+ };
74
+ });
75
+ });
76
+
77
+ // Given the current size of our icons (~5000 modules) we need to split up the
78
+ // entrypoint into chunks. In the past, we tried re-exporting from the source
79
+ // but this ended up causing slowdowns due to module resolution.
80
+ //
81
+ // As a result, we sort our list of modules into buckets and generate
82
+ // entrypoints based on those. Then, the root `index.js` file re-exports from
83
+ // these entrypoints. This is a hybrid approach between a single entrypoint
84
+ // that is too big for most tooling, and a re-export strategy that takes too
85
+ // long due to the number of modules along with the time it takes tooling to
86
+ // process them.
87
+ const BUCKET_SIZE = 250;
88
+ const BUCKET_COUNT = Math.ceil(modules.length / BUCKET_SIZE);
89
+ const buckets = Array(BUCKET_COUNT);
90
+
91
+ for (let i = 0; i < buckets.length; i++) {
92
+ const start = BUCKET_SIZE * i;
93
+ const end = Math.min(start + BUCKET_SIZE, modules.length) - 1;
94
+ const bucket = Array(end - start + 1);
95
+
96
+ for (let j = start; j <= end; j++) {
97
+ bucket[j - start] = modules[j];
98
+ }
99
+
100
+ buckets[i] = bucket;
101
+ }
102
+
103
+ const files = {
104
+ "index.ts": `${BANNER}\n\nexport { default as Icon } from './Icon.tsx';`,
105
+ };
106
+ const input = {
107
+ "index.js": "index.ts",
108
+ "Icon.js": "./Icon.tsx",
109
+ };
110
+ for (const m of modules) {
111
+ files[m.filepath] = m.entrypoint;
112
+ input[m.filepath] = m.filepath;
113
+ }
114
+
115
+ for (let i = 0; i < buckets.length; i++) {
116
+ const bucket = buckets[i];
117
+ const filename = `__generated__/bucket-${i}.js`;
118
+
119
+ input[filename] = filename;
120
+ files[filename] = `${BANNER}
121
+
122
+ import React from 'react';
123
+ import Icon from './Icon.tsx';
124
+
125
+ const didWarnAboutDeprecation = {};`;
126
+
127
+ for (const m of bucket) {
128
+ files[filename] += `export ${m.source}`;
129
+ files["index.ts"] += `export { ${m.moduleName} } from '${filename}';`;
130
+ }
131
+ }
132
+
133
+ const bundle = await rollup({
134
+ input,
135
+ external,
136
+ plugins: [
137
+ virtual({
138
+ "./Icon.tsx": await fs.readFile(
139
+ path.resolve(__dirname, "./components/Icon.tsx"),
140
+ "utf8",
141
+ ),
142
+ ...files,
143
+ }),
144
+ babel(babelConfig),
145
+ ],
146
+ });
147
+
148
+ const bundles = [
149
+ {
150
+ directory: path.join(output, "es"),
151
+ format: "esm",
152
+ },
153
+ {
154
+ directory: path.join(output, "lib"),
155
+ format: "commonjs",
156
+ },
157
+ ];
158
+
159
+ for (const { directory, format } of bundles) {
160
+ const outputOptions = {
161
+ dir: directory,
162
+ format,
163
+ entryFileNames: "[name]",
164
+ banner: BANNER,
165
+ exports: "auto",
166
+ };
167
+
168
+ await bundle.write(outputOptions);
169
+ }
170
+
171
+ const umd = await rollup({
172
+ input: "index.ts",
173
+ external,
174
+ plugins: [
175
+ virtual({
176
+ "./Icon.tsx": await fs.readFile(
177
+ path.resolve(__dirname, "./components/Icon.tsx"),
178
+ "utf8",
179
+ ),
180
+ ...files,
181
+ }),
182
+ babel(babelConfig),
183
+ ],
184
+ });
185
+
186
+ await umd.write({
187
+ file: path.join(output, "umd/index.js"),
188
+ format: "umd",
189
+ name: "CarbonIconsReact",
190
+ globals: {
191
+ "@octaviaflow/icon-helpers": "CarbonIconHelpers",
192
+ "prop-types": "PropTypes",
193
+ react: "React",
194
+ },
195
+ });
196
+ }
197
+
198
+ /**
199
+ * Convert the given node to a JSX string source
200
+ * @param {object} node
201
+ * @returns {string}
202
+ */
203
+ function convertToJSX(node) {
204
+ const { elem, attrs } = node;
205
+ return `<${elem} ${formatAttributes(attrs)} />`;
206
+ }
207
+
208
+ const attributeDenylist = ["data", "aria"];
209
+
210
+ /**
211
+ * Determine if the given attribute should be transformed when being converted
212
+ * to a React prop or if we should pass it through as-is
213
+ * @param {string} attribute
214
+ * @returns {boolean}
215
+ */
216
+ function shouldTransformAttribute(attribute) {
217
+ return attributeDenylist.every((prefix) => !attribute.startsWith(prefix));
218
+ }
219
+
220
+ /**
221
+ * Serialize a given object of key, value pairs to an JSX-compatible string
222
+ * @param {object} attrs
223
+ * @returns {string}
224
+ */
225
+ function formatAttributes(attrs) {
226
+ return Object.keys(attrs).reduce((acc, key, index) => {
227
+ const attribute = shouldTransformAttribute(key)
228
+ ? `${camelCase(key)}="${attrs[key]}"`
229
+ : `${key}="${attrs[key]}"`;
230
+
231
+ if (index === 0) {
232
+ return attribute;
233
+ }
234
+ return acc + " " + attribute;
235
+ }, "");
236
+ }
237
+
238
+ function createIconFlatExport(moduleName, descriptor, isDeprecated = false) {
239
+ const deprecatedBlock = isDeprecated
240
+ ? `
241
+ if (__DEV__) {
242
+ if (!didWarnAboutDeprecation['${moduleName}']) {
243
+ didWarnAboutDeprecation['${moduleName}'] = true;
244
+ console.warn(
245
+ \`The ${moduleName} component has been deprecated and will be \` +
246
+ \`removed in the next major version of @octaviaflow/icons-react.\`
247
+ );
248
+ }
249
+ }
250
+ `
251
+ : "";
252
+ return createIconSource(moduleName, descriptor, deprecatedBlock);
253
+ }
254
+
255
+ function createIconEntrypoint(moduleName, descriptor, isDeprecated = false) {
256
+ const deprecatedPreamble = isDeprecated
257
+ ? "let didWarnAboutDeprecation = false;"
258
+ : "";
259
+ const deprecatedBlock = isDeprecated
260
+ ? `
261
+ if (__DEV__) {
262
+ if (!didWarnAboutDeprecation) {
263
+ didWarnAboutDeprecation = true;
264
+ console.warn(
265
+ \`The ${moduleName} component has been deprecated and will be \` +
266
+ \`removed in the next major version of @octaviaflow/icons-react.\`
267
+ );
268
+ }
269
+ }
270
+ `
271
+ : "";
272
+ const source = createIconSource(moduleName, descriptor, deprecatedBlock);
273
+ return `${BANNER}
274
+ import React from 'react';
275
+ import Icon from './Icon.tsx';
276
+ ${deprecatedPreamble}
277
+ ${source}
278
+ export default ${moduleName};
279
+ `;
280
+ }
281
+
282
+ /**
283
+ * Generate an icon component, which in our case is the string representation
284
+ * of the component, from a given moduleName and icon descriptor.
285
+ * @param {string} moduleName
286
+ * @param {object} descriptor
287
+ * @param {string} customBlock
288
+ */
289
+ function createIconSource(moduleName, descriptor, customBlock = "") {
290
+ const { attrs, content } = descriptor;
291
+ const { width, height, viewBox, ...rest } = attrs;
292
+ return `
293
+ const ${moduleName} = /*#__PURE__*/ React.forwardRef(
294
+ function ${moduleName}({ children, ...rest }, ref) {
295
+ ${customBlock}
296
+ return (
297
+ <Icon
298
+ width={${width}}
299
+ height={${height}}
300
+ viewBox="${viewBox}"
301
+ ${formatAttributes(rest)}
302
+ ref={ref}
303
+ {...rest}>
304
+ ${content.map(convertToJSX).join("\n")}
305
+ {children}
306
+ </Icon>
307
+ );
308
+ }
309
+ );
310
+ `;
311
+ }
312
+
313
+ module.exports = builder;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ import { IconProps } from './Icon';
11
+
12
+ export interface CarbonIconProps extends IconProps {
13
+ size?: number | string;
14
+ }
15
+
16
+ export type CarbonIconType = React.ForwardRefExoticComponent<
17
+ CarbonIconProps & React.RefAttributes<React.ReactSVGElement>
18
+ >;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ import { getAttributes } from '@octaviaflow/icon-helpers';
11
+ import PropTypes from 'prop-types';
12
+ import React from 'react';
13
+
14
+ export interface IconProps
15
+ extends Omit<React.SVGProps<React.ReactSVGElement>, 'ref' | 'tabIndex'> {
16
+ /**
17
+ * @see React.SVGAttributes.tabIndex
18
+ * @todo remove support for string in v12
19
+ */
20
+ tabIndex?: string | number | undefined;
21
+
22
+ title?: string | undefined;
23
+ }
24
+
25
+ const Icon = React.forwardRef(function Icon(
26
+ {
27
+ className,
28
+ children,
29
+ tabIndex,
30
+ xmlns = 'http://www.w3.org/2000/svg',
31
+ preserveAspectRatio = 'xMidYMid meet',
32
+ ...rest
33
+ }: IconProps,
34
+ ref: React.ForwardedRef<React.ReactSVGElement>
35
+ ) {
36
+ const { tabindex, ...attrs } = getAttributes({
37
+ ...rest,
38
+ tabindex: tabIndex,
39
+ });
40
+ const props: React.SVGProps<React.ReactSVGElement> = attrs;
41
+
42
+ if (className) {
43
+ props.className = className;
44
+ }
45
+
46
+ if (tabindex !== undefined && tabindex !== null) {
47
+ if (typeof tabindex === 'number') {
48
+ props.tabIndex = tabindex;
49
+ } else {
50
+ props.tabIndex = Number(tabIndex);
51
+ }
52
+ }
53
+
54
+ if (ref) {
55
+ props.ref = ref;
56
+ }
57
+
58
+ if (xmlns) {
59
+ props.xmlns = xmlns;
60
+ }
61
+
62
+ if (preserveAspectRatio) {
63
+ props.preserveAspectRatio = preserveAspectRatio;
64
+ }
65
+
66
+ return React.createElement('svg', props, children);
67
+ });
68
+
69
+ Icon.displayName = 'Icon';
70
+ Icon.propTypes = {
71
+ 'aria-hidden': PropTypes.oneOfType([
72
+ PropTypes.bool,
73
+ PropTypes.oneOf<'true' | 'false'>(['true', 'false']),
74
+ ]),
75
+ 'aria-label': PropTypes.string,
76
+ 'aria-labelledby': PropTypes.string,
77
+ children: PropTypes.node,
78
+ className: PropTypes.string,
79
+ height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
80
+ preserveAspectRatio: PropTypes.string,
81
+ tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
82
+ viewBox: PropTypes.string,
83
+ width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
84
+ xmlns: PropTypes.string,
85
+ };
86
+
87
+ export default Icon;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Copyright OctaviaFlow
3
+ * Author: Vishal Kumar
4
+ * Created: 11/November/2025
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ "use strict";
11
+
12
+ const babelConfig = {
13
+ babelrc: false,
14
+ exclude: /node_modules/,
15
+ presets: [
16
+ [
17
+ "@babel/preset-env",
18
+ {
19
+ targets: {
20
+ browsers: ["extends browserslist-config-octaviaflow"],
21
+ },
22
+ },
23
+ ],
24
+ "@babel/preset-react",
25
+ "@babel/preset-typescript",
26
+ ],
27
+ plugins: [
28
+ "@babel/plugin-transform-react-constant-elements",
29
+ "babel-plugin-dev-expression",
30
+ ],
31
+ babelHelpers: "bundled",
32
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
33
+ };
34
+
35
+ module.exports = {
36
+ babelConfig,
37
+ };