diff --git a/app/react/src/server/__mocks__/mockRules.ts b/app/react/src/server/__mocks__/mockRules.ts index 11319ec0536d..3c43a333672b 100644 --- a/app/react/src/server/__mocks__/mockRules.ts +++ b/app/react/src/server/__mocks__/mockRules.ts @@ -1,7 +1,7 @@ export default [ { parser: { requireEnsure: false } }, { - test: /\.(js|mjs|jsx)$/, + test: /\.(js|mjs|jsx|ts|tsx)$/, enforce: 'pre', use: [ { @@ -10,7 +10,6 @@ export default [ eslintPath: '/mock_folder/node_modules/eslint/lib/api.js', baseConfig: { extends: ['/mock_folder/node_modules/eslint-config-react-app/index.js'], - settings: { react: { version: '999.999.999' } }, }, ignore: false, useEslintrc: false, @@ -44,7 +43,7 @@ export default [ { loaderMap: { svg: { - ReactComponent: '@svgr/webpack?-prettier,-svgo![path]', + ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]', }, }, }, diff --git a/app/react/src/server/cra-config.test.ts b/app/react/src/server/cra-config.test.ts index 35eb39a0db03..20feeab66037 100644 --- a/app/react/src/server/cra-config.test.ts +++ b/app/react/src/server/cra-config.test.ts @@ -83,18 +83,16 @@ exit $ret` describe('when used with TypeScript', () => { it('should return the correct config', () => { - // Normalise the return, as we know our new rules object will be an array, whereas a string is expected. const rules = getTypeScriptRules(mockRules, './.storybook'); - const rulesObject = { ...rules[0], include: rules[0].include[0] }; - expect(rulesObject).toMatchObject(mockRules[2].oneOf[1]); + expect(rules.length).toBe(2); }); // Allows using TypeScript in the `.storybook` (or config) folder. - it('should add the Storybook config directory to `include`', () => { + it('should add the Storybook config directory to `include` for all TS related rules', () => { const rules = getTypeScriptRules(mockRules, './.storybook'); - expect(rules[0].include.findIndex((string: string) => string.includes('.storybook'))).toEqual( - 1 - ); + expect( + rules.every(rule => rule.include.find(filePath => filePath.includes('.storybook'))) + ).toBe(true); }); it('should get the baseUrl from a tsconfig.json', () => { diff --git a/app/react/src/server/cra-config.ts b/app/react/src/server/cra-config.ts index 5c3ac9861976..b38418da6bc0 100644 --- a/app/react/src/server/cra-config.ts +++ b/app/react/src/server/cra-config.ts @@ -71,43 +71,53 @@ export function isReactScriptsInstalled(requiredVersion = '2.0.0') { } export const getRules = (extensions: string[]) => (rules: RuleSetRule[]) => - rules.reduce((craRules: any, rule: any) => { - // If at least one extension satisfies the rule test, the rule is one - // we want to extract - if (rule.test && extensions.some(normalizeCondition(rule.test))) { - // If the base test is for extensions, return early - return craRules.concat(rule); - } + rules.reduce( + (craRules, rule) => { + // If at least one extension satisfies the rule test, the rule is one + // we want to extract + if (rule.test && extensions.some(normalizeCondition(rule.test))) { + // If the base test is for extensions, return early + return craRules.concat(rule); + } - // Get any rules contained in rule.oneOf - if (!rule.test && rule.oneOf) { - craRules.push(...getRules(extensions)(rule.oneOf)); - } + // Get any rules contained in rule.oneOf + if (!rule.test && rule.oneOf) { + craRules.push(...getRules(extensions)(rule.oneOf)); + } - // Get any rules contained in rule.rules - if (!rule.test && rule.rules) { - craRules.push(...getRules(extensions)(rule.rules)); - } + // Get any rules contained in rule.rules + if (!rule.test && rule.rules) { + craRules.push(...getRules(extensions)(rule.rules)); + } - return craRules; - }, []); + return craRules; + }, + [] as RuleSetRule[] + ); const getStyleRules = getRules(cssExtensions.concat(cssModuleExtensions)); export const getTypeScriptRules = (webpackConfigRules: RuleSetRule[], configDir: string) => { const rules = getRules(typeScriptExtensions)(webpackConfigRules); - // We know CRA only has one rule targeting TS for now, which is the first rule. - const babelRule = rules[0]; - // Resolves an issue where this config is parsed twice (#4903). - if (typeof babelRule.include !== 'string') return rules; + // Adds support for using TypeScript in the `.storybook` (or config) folder. - return [ - { - ...babelRule, - include: [babelRule.include, path.resolve(configDir)], + return rules.reduce( + (accRules, rule) => { + // Resolves an issue where this config is parsed twice (#4903). + if (typeof rule.include !== 'string') { + return [...accRules, rule]; + } + + return [ + ...accRules, + { + ...rule, + include: [rule.include, path.resolve(configDir)], + }, + ]; }, - ...rules.slice(1), - ]; + [] as RuleSetRule[] + ); }; export const getModulePath = () => {