张嘉永
张嘉永

Reputation: 41

How to know if a variable is a global variable when writing a babel plug-in

I want to write a babel plugin that blocks global variables such as document and xhr from part of the code。 But I don't know how to tell if it belongs to window.

Example:

function queryClass(name){
  return document.querySelector(`.${name}`);
  // or return window.document.querySelector(`.${name}`)
}

I hope it turns into this

function queryClass(name){
  return noDocument.querySelector(`.${name}`);
  // or return window.noDocument.querySelector(`.${name}`)
}

But I don't want this code to be converted:

const document = {querySelector(str){return str + '1'}}
function queryClass(name){
  return document.querySelector(`.${name}`);
  // or return obj.document.querySelector(`.${name}`)
} 

So I think I should learn to judge if it's a global variable. Or is there any other way to help me achieve this? This is my simple babel code:

const babel = require("@babel/core");

const code = `
  function queryClass(name){
    return window.document.querySelector(\`.\${name}\`);
  }
`;

const visitor = {
  Identifier(path) {
    if(path.isIdentifier({name: 'document'})){
      // How to judge if it's a global variable
      path.node.name = 'noDocument';
    }
  }
}

const result = babel.transform(code, {
  plugins: [{visitor}]
});

Upvotes: 1

Views: 1062

Answers (2)

Sr. Oshiro
Sr. Oshiro

Reputation: 160

I'm new to babel plugin too
I think that is the way:

// inside Identifier(path)
const binding = path.scope.getBinding('document')
if (!binding) {
    // global
} else {
    // declaration point
    console.log(binding.identifier.loc)
}

Upvotes: 0

张嘉永
张嘉永

Reputation: 41

I just find a way to do this.

I don't know if it's a good idea.

const babel = require("@babel/core");

const code = `
  function queryClass(name){
    return window.document.querySelector(\`.\${name}\`);
  }
`;

const updateParamNameVisitor = {
  Identifier(path) {
    if (path.node.name === this.from) {
      path.replaceWith(this.to);
    }
  }
};

const visitor = {
  Program(path){
    if(path.scope.globals.document){
      const node = path.scope.generateUidIdentifier('no_document');
      path.traverse(updateParamNameVisitor, { from: 'document', to: node })
    }
  }
}

const result = babel.transform(code, {
  plugins: [{visitor}]
});

Upvotes: 2

Related Questions