Repository: microsoft/TypeScript
File: src/compiler/transformers/jsx.ts (TypeScript)

Code before:
        );
    }

    /**
     * The react jsx/jsxs transform falls back to `createElement` when an explicit `key` argument comes after a spread
     */
    function hasKeyAfterPropsSpread(node: JsxOpeningLikeElement) {
        let spread = false;
        for (const elem of node.attributes.properties) {
            if (isJsxSpreadAttribute(elem) && (!isObjectLiteralExpression(elem.expression) || elem.expression.properties.some(isSpreadAssignment))) {
                spread = true;
            }
            else if (spread && isJsxAttribute(elem) && isIdentifier(elem.name) && elem.name.escapedText === "key") {
                return true;
            }
        }
        return false;
    }

    function shouldUseCreateElement(node: JsxOpeningLikeElement) {
        return currentFileState.importSpecifier === undefined || hasKeyAfterPropsSpread(node);
    }

    function visitJsxElement(node: JsxElement, isChild: boolean) {
        const tagTransform = shouldUseCreateElement(node.openingElement) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX;
        return tagTransform(node.openingElement, node.children, isChild, /*location*/ createRange(getTokenPosOfNode(node, currentSourceFile), node.end));
    }

    function visitJsxSelfClosingElement(node: JsxSelfClosingElement, isChild: boolean) {
        const tagTransform = shouldUseCreateElement(node) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX;
        return tagTransform(node, /*children*/ undefined, isChild, /*location*/ createRange(getTokenPosOfNode(node, currentSourceFile), node.end));
    }

    function visitJsxFragment(node: JsxFragment, isChild: boolean) {
        const tagTransform = currentFileState.importSpecifier === undefined ? visitJsxOpeningFragmentCreateElement : visitJsxOpeningFragmentJSX;
        return tagTransform(node.openingFragment, node.children, isChild, /*location*/ createRange(getTokenPosOfNode(node, currentSourceFile), node.end));
    }

    function convertJsxChildrenToChildrenPropObject(children: readonly JsxChild[]) {
        const prop = convertJsxChildrenToChildrenPropAssignment(children);
        return prop && factory.createObjectLiteralExpression([prop]);
    }

    function convertJsxChildrenToChildrenPropAssignment(children: readonly JsxChild[]) {
        const nonWhitespaceChildren = getSemanticJsxChildren(children);
        if (length(nonWhitespaceChildren) === 1 && !(nonWhitespaceChildren[0] as JsxExpression).dotDotDotToken) {
            const result = transformJsxChildToExpression(nonWhitespaceChildren[0]);
            return result && factory.createPropertyAssignment("children", result);
        }
        const result = mapDefined(children, transformJsxChildToExpression);
        return length(result) ? factory.createPropertyAssignment("children", factory.createArrayLiteralExpression(result)) : undefined;

Review comment (suggestion):
`getTokenPosOfNode` works, but `skipTrivia` is what I think I would have used for this.

Code after:
        );
    }

    /**
     * The react jsx/jsxs transform falls back to `createElement` when an explicit `key` argument comes after a spread
     */
    function hasKeyAfterPropsSpread(node: JsxOpeningLikeElement) {
        let spread = false;
        for (const elem of node.attributes.properties) {
            if (isJsxSpreadAttribute(elem) && (!isObjectLiteralExpression(elem.expression) || elem.expression.properties.some(isSpreadAssignment))) {
                spread = true;
            }
            else if (spread && isJsxAttribute(elem) && isIdentifier(elem.name) && elem.name.escapedText === "key") {
                return true;
            }
        }
        return false;
    }

    function shouldUseCreateElement(node: JsxOpeningLikeElement) {
        return currentFileState.importSpecifier === undefined || hasKeyAfterPropsSpread(node);
    }

    function visitJsxElement(node: JsxElement, isChild: boolean) {
        const tagTransform = shouldUseCreateElement(node.openingElement) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX;
        return tagTransform(node.openingElement, node.children, isChild, /*location*/ createRange(skipTrivia(currentSourceFile.text, node.pos), node.end));
    }

    function visitJsxSelfClosingElement(node: JsxSelfClosingElement, isChild: boolean) {
        const tagTransform = shouldUseCreateElement(node) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX;
        return tagTransform(node, /*children*/ undefined, isChild, /*location*/ createRange(skipTrivia(currentSourceFile.text, node.pos), node.end));
    }

    function visitJsxFragment(node: JsxFragment, isChild: boolean) {
        const tagTransform = currentFileState.importSpecifier === undefined ? visitJsxOpeningFragmentCreateElement : visitJsxOpeningFragmentJSX;
        return tagTransform(node.openingFragment, node.children, isChild, /*location*/ createRange(skipTrivia(currentSourceFile.text, node.pos), node.end));
    }

    function convertJsxChildrenToChildrenPropObject(children: readonly JsxChild[]) {
        const prop = convertJsxChildrenToChildrenPropAssignment(children);
        return prop && factory.createObjectLiteralExpression([prop]);
    }

    function convertJsxChildrenToChildrenPropAssignment(children: readonly JsxChild[]) {
        const nonWhitespaceChildren = getSemanticJsxChildren(children);
        if (length(nonWhitespaceChildren) === 1 && !(nonWhitespaceChildren[0] as JsxExpression).dotDotDotToken) {
            const result = transformJsxChildToExpression(nonWhitespaceChildren[0]);
            return result && factory.createPropertyAssignment("children", result);
        }
        const result = mapDefined(children, transformJsxChildToExpression);
        return length(result) ? factory.createPropertyAssignment("children", factory.createArrayLiteralExpression(result)) : undefined;