wix-incubator / vscode-glean

The extension provides refactoring tools for your React codebase

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unexpected token, expected "," while converting from class to functional component

danielo515 opened this issue · comments

This is the error I see on the console:

Unexpected token, expected "," (1:30)
onDidChangeNotification @ notificationsAlerts.ts:40
(anonymous) @ notificationsAlerts.ts:26
fire @ event.ts:622
addNotification @ notifications.ts:206
notify @ notificationService.ts:103
(anonymous) @ mainThreadMessageService.ts:83
_showMessage @ mainThreadMessageService.ts:44
$showMessage @ mainThreadMessageService.ts:38
_doInvokeHandler @ rpcProtocol.ts:417
_invokeHandler @ rpcProtocol.ts:402
_receiveRequest @ rpcProtocol.ts:318
_receiveOneMessage @ rpcProtocol.ts:245
(anonymous) @ rpcProtocol.ts:110
fire @ event.ts:622
fire @ ipc.net.ts:468
_receiveMessage @ ipc.net.ts:821
(anonymous) @ ipc.net.ts:660
fire @ event.ts:622
acceptChunk @ ipc.net.ts:241
(anonymous) @ ipc.net.ts:202
I @ ipc.net.ts:32
emit @ events.js:315
addChunk @ _stream_readable.js:295
readableAddChunk @ _stream_readable.js:271
Readable.push @ _stream_readable.js:212
onStreamRead @ internal/stream_base_commons.js:186

Here is a small reproduction example:

type Props = {
  isOpen: boolean,
  toggleModal: Function,
  isLoading: boolean,
  onSubmit: Function,

  employee: Employee,
  payrollPeriod: PayrollPeriod,
}

class TerminationModal extends Component<Props> {
  constructor(props) {
    super(props)
    this.state = {
      isDateStepDone: props.form.getData('date'),
    }
  }

  render() {
    const {
      __,
      isOpen,
      toggleModal,
    } = this.props
    return (
      <Modal isOpen={isOpen} toggleModal={toggleModal}>
        <ModalHeader>
          <ModalTitle>{__('title')}</ModalTitle>
        </ModalHeader>
        <ModalBody>Body</ModalBody>
        <ModalFooter>Footer</ModalFooter>
      </Modal>
    )
  }
}

export default polyglotProvider(phrases)(ControlledForm(TerminationModal))

@danielo515 hey. Will check it out :) I assume you tried to convert this to functional component?

Yes, exactly. Sorry for not clarify that

Hello, anyone had a chance to take a look at this?

@danielo515 hey! Ive just tried to convert your code, and succeeded to do so. Tested on version 5.2.2.
Did u select just the class or the whole content?

I just selected the class. Should I select the whole thing?

nope. That should be fine. Ill check it out ASAP

Hello.
I did some more research on this and I am finding confusing conclusions...
I cloned the repository of the extension, ran a debug session and indeed it fails. I tried debugging the babel code, but it is quite hard, and it usually freezes my debugging session. After a while, I got frustrated, so I put a debug breakpoint before the const ast = codeToAst(component); line, copied the component code, pasted it into one of the extension tests and ran the tests. The test failed, as I expected, but it failed with the correct modified component being a function.
So, for some reason, something when running it on the extension mode makes it fail with a parsing error. It is very hard to narrow, but I'll keep trying

Ok, I found the root of the problem, it is not on the component conversion phase, it happens on this function:

  function importHooks(...hooks) {
    const currentFile = activeURI().fsPath;
    const file = readFileContent(currentFile);
    const ast = codeToAst(file);
    const reactImport = getReactImportReference(ast);
    hooks.forEach((hook) => {
      reactImport.specifiers.push(
        t.importSpecifier(t.identifier(hook), t.identifier(hook))
      );
    });

    const updatedReactImport = transformFromAst(t.program([reactImport])).code;
    return replaceTextInFile(
      updatedReactImport,
      new Position(reactImport.loc.start.line, reactImport.loc.start.column),
      new Position(reactImport.loc.end.line, reactImport.loc.end.column),
      activeFileName()
    );
  }
}

Specifically on this line: const ast = codeToAst(file);. There is something on the entire file that makes the parser to fail. I checked the line where it complains and I didn't saw anything wrong. In fact, this file compiles properly without problem on my TS pipeline, so it should be some missconfiguration on the babel

I modified the code of the mentioned function like this:

    let ast;
    try {
      ast = codeToAst(file);
    } catch (e) {
      console.log("Error parsing the entire file");
      vscode.env.clipboard.writeText(file);
      return () => {};
    }

And it modifies the component perfectly, but it does't add the missing imports, which compared to having to convert the component manually it is not a big deal for me. I added the copy to clipboard part to check that the content the parser is getting is correct, and indeed I copied it to the babel repl and it compiles without any problem, I am not sure what can be wrong with the parser within this extension.
Will you be open to accept a PR to include this or a similar modification?

Good and bad news 😄
The good news is that, while debugging this problem once more, I decided to update babel to a newer version (7.16.x), and that fixes the problem. It no longer throws an unexpected token error.
The bad news is that newer babel versions seems to have some breaking changes on their API, because some parts of the code now complain about providing wrong argument types, but it may be just the types...

@borislit will you be open to review a PR to fix this?