Repository: i18next/i18next-parser (js)

Issue:
Cannot read property 'text' of undefined in jsx-lexer
<!--
Before you submit an issue we recommend you visit [docs](https://www.i18next.com/) or [docs](https://react.i18next.com/) or [StackOverflow](https://stackoverflow.com/) or similar and ask any questions you have or mention any problems you've had getting started with i18next.

**Please read this entire template before posting any issue. If you ignore these instructions and post an issue here that does not follow the instructions, your issue might be closed, locked.**
-->

## 🐛 Bug Report

Same behavior as https://github.com/i18next/i18next-parser/issues/199 where the spread operator generates an error using i18next CLI on `v4.1.1`


## To Reproduce

```
import React from 'react';
import PropTypes from 'prop-types';
import { withTranslation, Trans } from 'react-i18next';

// Refer to https://react.i18next.com/latest/trans-component#alternative-usage-components-array
const Component = (props) => {
  return <Trans {...props}>{props.children}</Trans>;
};

Component.propTypes = {
  children: PropTypes.node.isRequired
};

export default withTranslation()(Component);
```

Once I remove the `{...props}`, then this error disappears.

## Expected behavior

There should be no error.

## Your Environment

- *runtime version*: i.e. node v12.21
- *i18next version*: i.e. 19.5.3
- *os*: Mac
- *any other relevant information*: the workaround is to remove the spread operator.


Pull request:
Fix: do not fail on JSX spread attribute in Trans component
### Why am I submitting this PR

#367

### Does it fix an existing ticket?

Yes, it fixes #367

### Checklist

- [x] only relevant code is changed (make a diff before you submit the PR)
- [x] tests are included and pass: `yarn test` (see [details here](https://github.com/i18next/i18next-parser/blob/master/docs/development.md#tests))
- [ ] documentation is changed or added


Patch:
diff --git a/src/lexers/jsx-lexer.js b/src/lexers/jsx-lexer.js
index 5a31e76..37c9dd8 100644
--- a/src/lexers/jsx-lexer.js
+++ b/src/lexers/jsx-lexer.js
@@ -64,9 +64,9 @@ export default class JsxLexer extends JavascriptLexer {
   jsxExtractor(node, sourceText) {
     const tagNode = node.openingElement || node
 
-    const getPropValue = (node, tagName) => {
+    const getPropValue = (node, attributeName) => {
       const attribute = node.attributes.properties.find(
-        (attr) => attr.name.text === tagName
+        (attr) => attr.name !== undefined && attr.name.text === attributeName
       )
       if (!attribute) {
         return undefined
@@ -109,6 +109,14 @@ export default class JsxLexer extends JavascriptLexer {
       }
 
       tagNode.attributes.properties.forEach((property) => {
+        if (property.kind === ts.SyntaxKind.JsxSpreadAttribute) {
+          this.emit(
+            'warning',
+            `Component attribute is a JSX spread attribute : ${property.expression.text}`
+          )
+          return
+        }
+
         if (this.omitAttributes.includes(property.name.text)) {
           return
         }


Test patch:
diff --git a/test/lexers/jsx-lexer.test.js b/test/lexers/jsx-lexer.test.js
index 8b13057..74c86aa 100644
--- a/test/lexers/jsx-lexer.test.js
+++ b/test/lexers/jsx-lexer.test.js
@@ -221,6 +221,19 @@ describe('JsxLexer', () => {
       ])
       done()
     })
+
+    it('emits a `warning` event if the component attribute is a JSX spread attribute', (done) => {
+      const Lexer = new JsxLexer()
+      const content = '<Trans defaults="bar" {...spread} />'
+      Lexer.on('warning', (message) => {
+        assert.equal(
+          message,
+          'Component attribute is a JSX spread attribute : spread'
+        )
+        done()
+      })
+      assert.deepEqual(Lexer.extract(content), [{ defaultValue: 'bar' }])
+    })
   })
 
   describe('supports TypeScript', () => {