aboutsummaryrefslogtreecommitdiff
path: root/node_modules/@ava/babel-plugin-throws-helper/index.js
blob: e370480f168cbbf8fde1e382cccd994b49244997 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
'use strict';

module.exports = babelCore => {
	const t = babelCore.types;
	const wrapArg = babelCore.template('(START(t, ASSERTION, FILE, LINE), END(t, ARG))');
	const helpers = babelCore.template(`function START(t, assertion, file, line) {
  if (t._throwsArgStart) {
    t._throwsArgStart(assertion, file, line);
  }
}

function END(t, arg) {
  if (t._throwsArgEnd) {
    t._throwsArgEnd();
  }

  return arg;
}`);

	const assertionVisitor = {
		CallExpression(path, state) {
			const callee = path.get('callee');
			if (!callee.isMemberExpression() || !callee.get('object').isIdentifier({name: 't'}) || !callee.get('property').isIdentifier()) {
				return;
			}

			const assertion = callee.get('property').get('name').node;
			if (assertion !== 'throws' && assertion !== 'notThrows') {
				return;
			}

			const arg0 = path.node.arguments[0];
			if (!(arg0 && arg0.loc && (typeof arg0.start === 'number') && (typeof arg0.end === 'number'))) {
				return;
			}

			// Wrap the argument expression, so that the stack trace of the assertion
			// isn't affected.
			path.node.arguments[0] = wrapArg(Object.assign({
				ARG: arg0,
				ASSERTION: t.stringLiteral(assertion),
				FILE: t.stringLiteral(state.file.opts.filename),
				LINE: t.numericLiteral(arg0.loc.start.line)
			}, this.installHelper())).expression;
		}
	};

	return {
		visitor: {
			Program(path, state) {
				const START = t.identifier(path.scope.generateUid('avaThrowsHelperStart'));
				const END = t.identifier(path.scope.generateUid('avaThrowsHelperEnd'));
				const helperIdentifiers = {START, END};

				let created = false;
				path.traverse(assertionVisitor, {
					installHelper() {
						if (!created) {
							created = true;
							path.unshiftContainer('body', helpers(helperIdentifiers));
						}

						return helperIdentifiers;
					},
					file: state.file
				});
			}
		}
	};
};