0

I'm trying to convert some Ember codes to React. Here is what I want to transform.

From

export default Ember.Component.extend(({
    didInsertElement() { }
});

To

export default class MyComponent extends React.Component {
    componentDidMount() { }
}

I write a babel plugin, and try to replace the Ember.Component.extend call with an AST node which is produced by template method. Here is the code snippet.

babel-plugin

const { default: template } = require("@babel/template");

const code = `class TestComponent extends React.Component { 
   componentDidMount() { }
 }`;
let classDeclarationNode = template.ast(code);
module.exports = function ({ types: t }) {
    return {
        visitor: {
            CallExpression(path) {
                if (!path.getSource().startsWith("Ember.Component.extend")) {
                    return;
                }
                path.replaceWith(classDeclarationNode);
            }
        }
    };
};

Output

export default (function () {
  class TestComponent extends React.Component {
    componentDidMount() {}
  }
})();

Instead of the expected code I wrote above, I get the ClassDeclaration statement surrounded with IIFE. Is there any way to remove the IIFE?

I have struggled with the problem one whole day, but have no way to resolve it.


BTW, I also tried parseExpression method, but still can't get what exactly I want.

babel-plugin

const { parseExpression } = require('@babel/parser');

const code = `class TestComponent extends React.Component { 
    componentDidMount() { }
}`;
let expression = parseExpression(code);
module.exports = function ({ types: t }) {
    return {
        visitor: {
            CallExpression(path) {
                if (!path.getSource().startsWith("Ember.Component.extend")) {
                    return;
                }
                path.replaceWith(expression);
            }
        }
    };
};

Output

export default (class TestComponent extends React.Component {
  componentDidMount() {}
});

It's quite close to the correct code, except an extra pair of (). Is there any way to generate the pure class declaration?

shijistar
  • 111
  • 4

1 Answers1

1

Thanks for the help of loganfsmyth on Slack, the problem was finally resolved. I should replace the node of whole export default but not only the CallExpression. Here is the code.

babel-plugin

const { default: template } = require("@babel/template");

const code = `export default class TestComponent extends React.Component { 
   componentDidMount() { }
 }`;
let rootNode = template.ast(code);
module.exports = function ({ types: t }) {
    return {
        visitor: {
            ExportDefaultDeclaration(path) {
                let isMatchedNode = (path.node.declaration &&
                    t.matchesPattern(path.node.declaration.callee, "Ember.Component.extend"));
                if (!isMatchedNode) {
                    return;
                }
                path.replaceWith(rootNode);
            }
        }
    };
};

Output

export default class TestComponent extends React.Component {
  componentDidMount() {}
}

shijistar
  • 111
  • 4