index.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use strict';
  2. var parser = require('acorn');
  3. require('acorn-es7-plugin')(parser);
  4. var estraverse = require('estraverse');
  5. var purifyAst = require('espurify').customize({extra: ['range']});
  6. var assign = require('core-js/library/fn/object/assign');
  7. module.exports = function (powerAssertContext) {
  8. var source = powerAssertContext.source;
  9. if (source.ast && source.tokens && source.visitorKeys) {
  10. return powerAssertContext;
  11. }
  12. var astAndTokens;
  13. try {
  14. astAndTokens = parse(source);
  15. } catch (e) {
  16. return assign({}, powerAssertContext, { source: assign({}, source, { error: e }) });
  17. }
  18. var newSource = assign({}, source, {
  19. ast: purifyAst(astAndTokens.expression),
  20. tokens: astAndTokens.tokens,
  21. visitorKeys: estraverse.VisitorKeys
  22. });
  23. return assign({}, powerAssertContext, { source: newSource });
  24. };
  25. function parserOptions(tokens) {
  26. return {
  27. sourceType: 'module',
  28. ecmaVersion: 2018,
  29. locations: true,
  30. ranges: false,
  31. onToken: tokens,
  32. plugins: {asyncawait: true}
  33. };
  34. }
  35. function parse (source) {
  36. var code = source.content;
  37. var ast, tokens;
  38. function doParse(wrapper) {
  39. var content = wrapper ? wrapper(code) : code;
  40. var tokenBag = [];
  41. ast = parser.parse(content, parserOptions(tokenBag));
  42. if (wrapper) {
  43. ast = ast.body[0].body;
  44. tokens = tokenBag.slice(6, -2);
  45. } else {
  46. tokens = tokenBag.slice(0, -1);
  47. }
  48. }
  49. if (source.async) {
  50. doParse(wrappedInAsync);
  51. } else if (source.generator) {
  52. doParse(wrappedInGenerator);
  53. } else {
  54. doParse();
  55. }
  56. var exp = ast.body[0].expression;
  57. var columnOffset = exp.loc.start.column;
  58. var offsetTree = estraverse.replace(exp, {
  59. keys: estraverse.VisitorKeys,
  60. enter: function (eachNode) {
  61. if (!eachNode.loc && eachNode.range) {
  62. // skip already visited node
  63. return eachNode;
  64. }
  65. eachNode.range = [
  66. eachNode.loc.start.column - columnOffset,
  67. eachNode.loc.end.column - columnOffset
  68. ];
  69. delete eachNode.loc;
  70. return eachNode;
  71. }
  72. });
  73. return {
  74. tokens: offsetAndSlimDownTokens(tokens),
  75. expression: offsetTree
  76. };
  77. }
  78. function wrappedInGenerator (jsCode) {
  79. return 'function *wrapper() { ' + jsCode + ' }';
  80. }
  81. function wrappedInAsync (jsCode) {
  82. return 'async function wrapper() { ' + jsCode + ' }';
  83. }
  84. function offsetAndSlimDownTokens (tokens) {
  85. var i, token, newToken, result = [];
  86. var columnOffset;
  87. for(i = 0; i < tokens.length; i += 1) {
  88. token = tokens[i];
  89. if (i === 0) {
  90. columnOffset = token.loc.start.column;
  91. }
  92. newToken = {
  93. type: {
  94. label: token.type.label
  95. }
  96. };
  97. if (typeof token.value !== 'undefined') {
  98. newToken.value = token.value;
  99. }
  100. newToken.range = [
  101. token.loc.start.column - columnOffset,
  102. token.loc.end.column - columnOffset
  103. ];
  104. result.push(newToken);
  105. }
  106. return result;
  107. }