script.js 3.5 KB
Newer Older
C
init  
Conan 已提交
1 2
const parse = require('@babel/parser').parse;
const config = require('../config/parser-config');
3 4 5
const traverse = require('@babel/traverse')['default'];
const globalVars = require('../config/globalVars');
const uniq = require('lodash.uniq');
C
init  
Conan 已提交
6 7 8 9 10 11 12

const Map = {
  watch: 'watcher',
  computed: 'computed property',
  methods: 'method'
};

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
function checkArrowFun(path) {
  let messages = [];
  if (path.node) {
    let properties = path.get('value').get('properties');
    switch (path.node.key.name) {
      case 'watch':
      case 'computed':
      case 'methods':
        if (properties.forEach) {
          (properties || []).forEach(property => {
            messages = messages.concat(handleProperty(property, path.node.key.name));
          });
        }
        break;
      case 'beforeCreate':
      case 'created':
      case 'beforeMount':
      case 'mounted':
      case 'beforeDestroy':
      case 'destroyed':
        messages = messages.concat(handleProperty(path, path.node.key.name));
        break;
      default:
        break;
    }
  }
  return messages;
}

function handleProperty(property, propertyName) {
  let messages = [];
C
init  
Conan 已提交
44 45 46 47 48 49 50 51 52 53
  if (property.get('value').isArrowFunctionExpression()) {
    let node = property.get('key').node;
    let name = node.name;
    messages.push({
      line: node.loc.start.line,
      column: node.loc.start.column + 1,
      msg: Map[propertyName]
        ? (Map[propertyName] + ' "' + name + '" cannot be used as an arrow function')
        : ('lifecycle hook "' + name + '" cannot be used as an arrow function')
    });
54 55 56 57 58 59 60 61 62 63 64 65 66
  }
  return messages;
}

function getForbiddenGlobalTokens(platform = 'all') {
  let tokenList = [];
  platform = platform.toUpperCase();

  Object.keys(globalVars).forEach(key => {
    if (platform === 'ALL' || key !== platform) {
      tokenList = tokenList.concat(globalVars[key]);
    }
  });
C
init  
Conan 已提交
67

68 69 70 71 72 73 74 75
  tokenList = uniq(tokenList);

  return tokenList;
}


function checkGlobal(path, tokenList) {
  let messages = [];
76 77 78 79 80

  let programScope = path.scope;

  Object.keys(programScope.globals).forEach(tokenName => {
    if (~tokenList.indexOf(tokenName)) {
81
      messages.push({
82 83
        line: programScope.globals[tokenName].loc.start.line,
        column: programScope.globals[tokenName].loc.start.column,
84 85 86 87
        token: tokenName,
        msg: 'global variable: "' + tokenName + '" should not be used in this file'
      });
    }
88
  });
89 90 91

  return messages;
}
C
init  
Conan 已提交
92 93 94 95 96 97 98 99

/**
 * 校验语法
 *
 * @param  {Object} part 片段
 * @return {Object}      语法检查结果
 */
const checkSyntax = function (part) {
100
  let messages = [];
C
init  
Conan 已提交
101 102
  const opts = config.script;
  let ast;
103
  let tokenList = [];
C
init  
Conan 已提交
104 105 106 107 108 109 110 111 112 113
  try {
    ast = parse(part.content, opts);
  }
  catch (err) {
    messages.push({
      line: err.loc.line,
      column: err.loc.column + 1,
      msg: err.message.replace(/ \((\d+):(\d+)\)$/, '')
    });
  }
Q
quyatong 已提交
114
  try {
115
    tokenList = getForbiddenGlobalTokens(part.platformType || 'all');
Q
quyatong 已提交
116
    traverse(ast, {
117
      // check arrow function: we do not allow arrow functions in life cycle hooks.
118 119 120
      ClassProperty(path) {
        messages = messages.concat(checkArrowFun(path));
      },
121 122
      // check global variables: we shall never use any platform specified global variables such as wx, global, window etc.
      Program(path) {
123
        messages = messages.concat(checkGlobal(path, tokenList));
C
init  
Conan 已提交
124
      }
Q
quyatong 已提交
125 126 127 128 129
    });
  }
  catch (e) {
    console.log(e);
  }
C
init  
Conan 已提交
130 131 132 133 134 135 136 137 138 139 140 141


  return {
    start: part.line,
    ast,
    messages
  };
}

module.exports = function (part) {
  return checkSyntax(part);
};