Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot set property 'hasAwait' of null #12283

Closed
lll000111 opened this issue Sep 18, 2019 · 11 comments
Closed

Cannot set property 'hasAwait' of null #12283

lll000111 opened this issue Sep 18, 2019 · 11 comments
Labels
archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion rule Relates to ESLint's core rules

Comments

@lll000111
Copy link

lll000111 commented Sep 18, 2019

  • ESLint Version: v6.4.0
  • Node Version: v12.10.0
  • npm Version: 6.10.3

What parser (default, Babel-ESLint, etc.) are you using?

@typescript-eslint/parser

Please show your full configuration:
eslintrc

$ eslint  --ext .ts --ext .tsx src/
TypeError: Cannot set property 'hasAwait' of null
Occurred while linting /home/mha/Projects/chat/src/components/ChatMessage.tsx:127
    at AwaitExpression (/home/mha/Projects/chat/node_modules/eslint/lib/rules/require-await.js:95:36)
    at /home/mha/Projects/chat/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/home/mha/Projects/chat/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/home/mha/Projects/chat/node_modules/eslint/lib/linter/node-event-generator.js:253:26)
    at NodeEventGenerator.applySelectors (/home/mha/Projects/chat/node_modules/eslint/lib/linter/node-event-generator.js:282:22)
    at NodeEventGenerator.enterNode (/home/mha/Projects/chat/node_modules/eslint/lib/linter/node-event-generator.js:296:14)
    at CodePathAnalyzer.enterNode (/home/mha/Projects/chat/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:646:23)
    at /home/mha/Projects/chat/node_modules/eslint/lib/linter/linter.js:936:32
    at Array.forEach (<anonymous>)
@lll000111 lll000111 added bug ESLint is working incorrectly triage An ESLint team member will look at this issue soon labels Sep 18, 2019
@lll000111
Copy link
Author

Closing because I saw that function had pretty obvious issues — so, sorry, never mind.

@lll000111
Copy link
Author

Actually, maybe you want to let this not crash at least?

The problem was that the function (render(), React project) did is not async but somebody used await in the function body. Clearly an error of course, but maybe it should not crash eslint completely.

@lll000111 lll000111 reopened this Sep 18, 2019
@kaicataldo
Copy link
Member

This isn't currently handled by the rule because this is a parser error in the default parser and in Babel's parser (see demo). I don't think it would be a bad thing to update the rule to not crash here, but I think the real fix should be that @typescript-eslint/parser should throw a parser error here.

@kaicataldo kaicataldo added evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion rule Relates to ESLint's core rules and removed triage An ESLint team member will look at this issue soon labels Sep 18, 2019
@mdjermanovic
Copy link
Member

An interesting thing is that it seems that the rule in question require-await can survive the described scenario (await in a non-async function) and even work well for the rest of the same file.

The rule can crash on a top-level await, though. If this isn't an await outside of any functions, then it might be a completely broken AST.

@kaicataldo
Copy link
Member

@lll000111 Do you mind sharing the code (or a minimal repro case) that is causing this on your end?

@lll000111
Copy link
Author

lll000111 commented Sep 18, 2019

Here's the complete .tsx file. I'm not the author, I merely observe the project, and it is being transitioned to TypeScript. The crash was reported coming from line 127.

import React, {PureComponent, ReactElement} from 'react';
import {abToURL, download} from '../dom';
import * as types from '@OneCoreTypes';
import {ChatMessageProps} from '../propsTypes';
import {uGetObjectByHash} from '../one/worker/WorkerBridge';
import {Attachment} from '@OneCoreTypes';

/**
 *
 */
export function renderAttachment(
    attachments: Array<types.Attachment>,
    idx: number
): ReactElement | HTMLElement | any {
    if (attachments) {
        return attachments.map((attachment: types.Attachment, idx2: number) => {
            attachment.objUrl = abToURL(attachment.data.type);

            switch (attachment.dataType) {
                case 'video': {
                    return (
                        <video width={320} height={240} controls key={'a' + idx + idx2}>
                            <source src={attachment.objUrl} />
                        </video>
                    );
                }
                case 'image': {
                    return (
                        <img src={attachment.objUrl} alt="" height={300} key={'a' + idx + idx2} />
                    );
                }
                case 'audio': {
                    return (
                        <audio controls key={idx + idx2}>
                            <source src={attachment.objUrl} />
                        </audio>
                    );
                }
                default: {
                    return (
                        <a // eslint-disable-line
                            href="#"
                            onClick={() =>
                                download(
                                    attachment.data.type,
                                    attachment.filename,
                                    attachment.dataType
                                )
                            }
                            key={'a' + idx + idx2}
                        >
                            {attachment.filename}
                        </a>
                    );
                }
            }
        });
    }

    return;
}

export class ChatMessage extends PureComponent<ChatMessageProps> {
    renderMessage(): JSX.Element[] {
        const {message} = this.props.message;
        const {emojiMap, showEmoji} = this.props;
        const rgx = new RegExp('\\((\\w+)\\)', 'g');
        let start = 0;
        let match;
        let key = 0;
        const elems = [];

        while ((match = rgx.exec(message)) !== null) {
            elems.push(<span key={key++}>{message.substring(start, match.index)}</span>);

            const name = match[1];
            const emoji = emojiMap.get(name);

            if (emoji) {
                elems.push(
                    <img
                        key={key++}
                        src={emoji.smallImage}
                        alt={`${name} emoji`}
                        onClick={() => showEmoji(emoji)}
                        style={{height: '1.2em'}}
                    />
                );
            } else {
                elems.push(<span key={key++}>{match[0]}</span>);
            }
            start = rgx.lastIndex;
        }
        elems.push(<span key={key++}>{message.substring(start)}</span>);
        return elems;
    }

    render(): ReactElement | HTMLElement | undefined {
        const {message, idx, sourcePersonRes, partnerProfilePerson} = this.props;
        let senderName, me;

        if (partnerProfilePerson) {
            senderName = partnerProfilePerson.name;

            if (message.source === undefined) {
                return;
            }
            me = sourcePersonRes.type.email === message.source.type.email;
        }

        if (message.source) {
            me = sourcePersonRes.type.email === message.source.type.email;
            senderName = message.source.type.name;
        }

        const date = new Date(message.date);
        const now = new Date();
        const today =
            date.getDate() === now.getDate() &&
            date.getMonth() === now.getMonth() &&
            date.getFullYear() === now.getFullYear();
        const dt = today
            ? date.toLocaleTimeString('de-DE').substr(0, 5)
            : date.toLocaleDateString('de-DE');
        const color = me ? '#e91e63' : '#673ab7';

        const attachmentsArray = (await Promise.all(
            (message.attachments || []).map(idHash => uGetObjectByHash(idHash))
        )) as Attachment[];

        return (
            <div
                key={'m' + idx}
                style={{
                    display: 'flex',
                    width: '100%',
                    margin: '10px 0',
                    justifyContent: me ? 'flex-end' : 'flex-start'
                }}
            >
                <div
                    style={{
                        position: 'relative',
                        padding: 10,
                        borderRadius: 5,
                        backgroundColor: me ? '#f8bbd0' : '#d1c4e9',
                        minWidth: 125,
                        maxWidth: '80%'
                    }}
                >
                    <div style={{padding: '7px 0 5px 0'}}>
                        <strong style={{color}}>{me ? 'me' : senderName}</strong>
                        :&nbsp;
                        {this.renderMessage()}
                        <span>{renderAttachment(attachmentsArray, idx)}</span>
                    </div>
                    <span
                        style={{
                            position: 'absolute',
                            top: 0,
                            right: 0,
                            fontSize: '0.8em',
                            padding: '2px 5px',
                            color
                        }}
                    >
                        {dt}
                    </span>
                </div>
            </div>
        );
    }
}

@kaicataldo
Copy link
Member

Thanks. I made an issue and PR in the typescript-eslint repo.

@mdjermanovic
Copy link
Member

The project is actually using @typescript-eslint/require-await rule, not directly require-await. This rule internally uses the core require-await and also has some additional logic from the typing information (allows async functions without await in some cases).

Docs: @typescript-eslint/require-await.md

Source code: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/rules/require-await.ts

It doesn't appear in the stack trace because it just returns a reference to AwaitExpression. When the line AwaitExpression: rules.AwaitExpression in the distribution code is replaced with something like AwaitExpression(node){ rules.AwaitExpression(node); }, it does appear in the stack trace.

While the core rule doesn't crash on this code, the @typescript-eslint wrapper does, because it has a bit different selectors - FunctionExpression[async = true] instead of just FunctionExpression.

@kaicataldo
Copy link
Member

Thanks for the explanation! Sounds like it's indeed an issue for @typescript-eslint.

@ilyavolodin
Copy link
Member

Closing this issue, since the problem is in typescript-eslint

@biolauri
Copy link

I just want to link the issue on @typescript-eslint: typescript-eslint/typescript-eslint#1226 for reference and if anyone stumblesupon this.

By the way, the issue is already fixed and will be released on monday, as stated in typescript-eslint/typescript-eslint#1226 (comment).

@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Mar 24, 2020
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Mar 24, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion rule Relates to ESLint's core rules
Projects
None yet
Development

No branches or pull requests

5 participants