Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.getNodeName = getNodeName;
  6. exports.scopeHasLocalReference = exports.isDescribeCall = exports.isTestCaseCall = exports.getTestCallExpressionsFromDeclaredVariables = exports.isHook = exports.isFunction = exports.TestCaseProperty = exports.DescribeProperty = exports.HookName = exports.TestCaseName = exports.DescribeAlias = exports.parseExpectCall = exports.isParsedEqualityMatcherCall = exports.EqualityMatcher = exports.ModifierName = exports.isExpectMember = exports.isExpectCall = exports.getAccessorValue = exports.isSupportedAccessor = exports.hasOnlyOneArgument = exports.getStringValue = exports.isStringNode = exports.followTypeAssertionChain = exports.createRule = void 0;
  7. var _path = require("path");
  8. var _experimentalUtils = require("@typescript-eslint/experimental-utils");
  9. var _package = require("../../package.json");
  10. const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest';
  11. const createRule = _experimentalUtils.ESLintUtils.RuleCreator(name => {
  12. const ruleName = (0, _path.parse)(name).name;
  13. return `${REPO_URL}/blob/v${_package.version}/docs/rules/${ruleName}.md`;
  14. });
  15. exports.createRule = createRule;
  16. const isTypeCastExpression = node => node.type === _experimentalUtils.AST_NODE_TYPES.TSAsExpression || node.type === _experimentalUtils.AST_NODE_TYPES.TSTypeAssertion;
  17. const followTypeAssertionChain = expression => isTypeCastExpression(expression) ? followTypeAssertionChain(expression.expression) : expression;
  18. /**
  19. * A `Literal` with a `value` of type `string`.
  20. */
  21. exports.followTypeAssertionChain = followTypeAssertionChain;
  22. /**
  23. * Checks if the given `node` is a `StringLiteral`.
  24. *
  25. * If a `value` is provided & the `node` is a `StringLiteral`,
  26. * the `value` will be compared to that of the `StringLiteral`.
  27. *
  28. * @param {Node} node
  29. * @param {V} [value]
  30. *
  31. * @return {node is StringLiteral<V>}
  32. *
  33. * @template V
  34. */
  35. const isStringLiteral = (node, value) => node.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof node.value === 'string' && (value === undefined || node.value === value);
  36. /**
  37. * Checks if the given `node` is a `TemplateLiteral`.
  38. *
  39. * Complex `TemplateLiteral`s are not considered specific, and so will return `false`.
  40. *
  41. * If a `value` is provided & the `node` is a `TemplateLiteral`,
  42. * the `value` will be compared to that of the `TemplateLiteral`.
  43. *
  44. * @param {Node} node
  45. * @param {V} [value]
  46. *
  47. * @return {node is TemplateLiteral<V>}
  48. *
  49. * @template V
  50. */
  51. const isTemplateLiteral = (node, value) => node.type === _experimentalUtils.AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1 && (value === undefined || node.quasis[0].value.raw === value);
  52. /**
  53. * Checks if the given `node` is a {@link StringNode}.
  54. *
  55. * @param {Node} node
  56. * @param {V} [specifics]
  57. *
  58. * @return {node is StringNode}
  59. *
  60. * @template V
  61. */
  62. const isStringNode = (node, specifics) => isStringLiteral(node, specifics) || isTemplateLiteral(node, specifics);
  63. /**
  64. * Gets the value of the given `StringNode`.
  65. *
  66. * If the `node` is a `TemplateLiteral`, the `raw` value is used;
  67. * otherwise, `value` is returned instead.
  68. *
  69. * @param {StringNode<S>} node
  70. *
  71. * @return {S}
  72. *
  73. * @template S
  74. */
  75. exports.isStringNode = isStringNode;
  76. const getStringValue = node => isTemplateLiteral(node) ? node.quasis[0].value.raw : node.value;
  77. /**
  78. * Represents a `MemberExpression` with a "known" `property`.
  79. */
  80. exports.getStringValue = getStringValue;
  81. /**
  82. * Guards that the given `call` has only one `argument`.
  83. *
  84. * @param {CallExpression} call
  85. *
  86. * @return {call is CallExpressionWithSingleArgument}
  87. */
  88. const hasOnlyOneArgument = call => call.arguments.length === 1;
  89. /**
  90. * An `Identifier` with a known `name` value - i.e `expect`.
  91. */
  92. exports.hasOnlyOneArgument = hasOnlyOneArgument;
  93. /**
  94. * Checks if the given `node` is an `Identifier`.
  95. *
  96. * If a `name` is provided, & the `node` is an `Identifier`,
  97. * the `name` will be compared to that of the `identifier`.
  98. *
  99. * @param {Node} node
  100. * @param {V} [name]
  101. *
  102. * @return {node is KnownIdentifier<Name>}
  103. *
  104. * @template V
  105. */
  106. const isIdentifier = (node, name) => node.type === _experimentalUtils.AST_NODE_TYPES.Identifier && (name === undefined || node.name === name);
  107. /**
  108. * Checks if the given `node` is a "supported accessor".
  109. *
  110. * This means that it's a node can be used to access properties,
  111. * and who's "value" can be statically determined.
  112. *
  113. * `MemberExpression` nodes most commonly contain accessors,
  114. * but it's possible for other nodes to contain them.
  115. *
  116. * If a `value` is provided & the `node` is an `AccessorNode`,
  117. * the `value` will be compared to that of the `AccessorNode`.
  118. *
  119. * Note that `value` here refers to the normalised value.
  120. * The property that holds the value is not always called `name`.
  121. *
  122. * @param {Node} node
  123. * @param {V} [value]
  124. *
  125. * @return {node is AccessorNode<V>}
  126. *
  127. * @template V
  128. */
  129. const isSupportedAccessor = (node, value) => isIdentifier(node, value) || isStringNode(node, value);
  130. /**
  131. * Gets the value of the given `AccessorNode`,
  132. * account for the different node types.
  133. *
  134. * @param {AccessorNode<S>} accessor
  135. *
  136. * @return {S}
  137. *
  138. * @template S
  139. */
  140. exports.isSupportedAccessor = isSupportedAccessor;
  141. const getAccessorValue = accessor => accessor.type === _experimentalUtils.AST_NODE_TYPES.Identifier ? accessor.name : getStringValue(accessor);
  142. exports.getAccessorValue = getAccessorValue;
  143. /**
  144. * Checks if the given `node` is a valid `ExpectCall`.
  145. *
  146. * In order to be an `ExpectCall`, the `node` must:
  147. * * be a `CallExpression`,
  148. * * have an accessor named 'expect',
  149. * * have a `parent`.
  150. *
  151. * @param {Node} node
  152. *
  153. * @return {node is ExpectCall}
  154. */
  155. const isExpectCall = node => node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && isSupportedAccessor(node.callee, 'expect') && node.parent !== undefined;
  156. exports.isExpectCall = isExpectCall;
  157. const isExpectMember = (node, name) => node.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && isSupportedAccessor(node.property, name);
  158. /**
  159. * Represents all the jest matchers.
  160. */
  161. exports.isExpectMember = isExpectMember;
  162. let ModifierName;
  163. exports.ModifierName = ModifierName;
  164. (function (ModifierName) {
  165. ModifierName["not"] = "not";
  166. ModifierName["rejects"] = "rejects";
  167. ModifierName["resolves"] = "resolves";
  168. })(ModifierName || (exports.ModifierName = ModifierName = {}));
  169. let EqualityMatcher;
  170. exports.EqualityMatcher = EqualityMatcher;
  171. (function (EqualityMatcher) {
  172. EqualityMatcher["toBe"] = "toBe";
  173. EqualityMatcher["toEqual"] = "toEqual";
  174. EqualityMatcher["toStrictEqual"] = "toStrictEqual";
  175. })(EqualityMatcher || (exports.EqualityMatcher = EqualityMatcher = {}));
  176. const isParsedEqualityMatcherCall = (matcher, name) => (name ? matcher.name === name : EqualityMatcher.hasOwnProperty(matcher.name)) && matcher.arguments !== null && matcher.arguments.length === 1;
  177. /**
  178. * Represents a parsed expect matcher, such as `toBe`, `toContain`, and so on.
  179. */
  180. exports.isParsedEqualityMatcherCall = isParsedEqualityMatcherCall;
  181. const parseExpectMember = expectMember => ({
  182. name: getAccessorValue(expectMember.property),
  183. node: expectMember
  184. });
  185. const reparseAsMatcher = parsedMember => ({ ...parsedMember,
  186. /**
  187. * The arguments being passed to this `Matcher`, if any.
  188. *
  189. * If this matcher isn't called, this will be `null`.
  190. */
  191. arguments: parsedMember.node.parent && parsedMember.node.parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression ? parsedMember.node.parent.arguments : null
  192. });
  193. /**
  194. * Re-parses the given `parsedMember` as a `ParsedExpectModifier`.
  195. *
  196. * If the given `parsedMember` does not have a `name` of a valid `Modifier`,
  197. * an exception will be thrown.
  198. *
  199. * @param {ParsedExpectMember<ModifierName>} parsedMember
  200. *
  201. * @return {ParsedExpectModifier}
  202. */
  203. const reparseMemberAsModifier = parsedMember => {
  204. if (isSpecificMember(parsedMember, ModifierName.not)) {
  205. return parsedMember;
  206. }
  207. /* istanbul ignore if */
  208. if (!isSpecificMember(parsedMember, ModifierName.resolves) && !isSpecificMember(parsedMember, ModifierName.rejects)) {
  209. // ts doesn't think that the ModifierName.not check is the direct inverse as the above two checks
  210. // todo: impossible at runtime, but can't be typed w/o negation support
  211. throw new Error(`modifier name must be either "${ModifierName.resolves}" or "${ModifierName.rejects}" (got "${parsedMember.name}")`);
  212. }
  213. const negation = parsedMember.node.parent && isExpectMember(parsedMember.node.parent, ModifierName.not) ? parsedMember.node.parent : undefined;
  214. return { ...parsedMember,
  215. negation
  216. };
  217. };
  218. const isSpecificMember = (member, specific) => member.name === specific;
  219. /**
  220. * Checks if the given `ParsedExpectMember` should be re-parsed as an `ParsedExpectModifier`.
  221. *
  222. * @param {ParsedExpectMember} member
  223. *
  224. * @return {member is ParsedExpectMember<ModifierName>}
  225. */
  226. const shouldBeParsedExpectModifier = member => ModifierName.hasOwnProperty(member.name);
  227. const parseExpectCall = expect => {
  228. const expectation = {
  229. expect
  230. };
  231. if (!isExpectMember(expect.parent)) {
  232. return expectation;
  233. }
  234. const parsedMember = parseExpectMember(expect.parent);
  235. if (!shouldBeParsedExpectModifier(parsedMember)) {
  236. expectation.matcher = reparseAsMatcher(parsedMember);
  237. return expectation;
  238. }
  239. const modifier = expectation.modifier = reparseMemberAsModifier(parsedMember);
  240. const memberNode = modifier.negation || modifier.node;
  241. if (!memberNode.parent || !isExpectMember(memberNode.parent)) {
  242. return expectation;
  243. }
  244. expectation.matcher = reparseAsMatcher(parseExpectMember(memberNode.parent));
  245. return expectation;
  246. };
  247. exports.parseExpectCall = parseExpectCall;
  248. let DescribeAlias;
  249. exports.DescribeAlias = DescribeAlias;
  250. (function (DescribeAlias) {
  251. DescribeAlias["describe"] = "describe";
  252. DescribeAlias["fdescribe"] = "fdescribe";
  253. DescribeAlias["xdescribe"] = "xdescribe";
  254. })(DescribeAlias || (exports.DescribeAlias = DescribeAlias = {}));
  255. let TestCaseName;
  256. exports.TestCaseName = TestCaseName;
  257. (function (TestCaseName) {
  258. TestCaseName["fit"] = "fit";
  259. TestCaseName["it"] = "it";
  260. TestCaseName["test"] = "test";
  261. TestCaseName["xit"] = "xit";
  262. TestCaseName["xtest"] = "xtest";
  263. })(TestCaseName || (exports.TestCaseName = TestCaseName = {}));
  264. let HookName;
  265. exports.HookName = HookName;
  266. (function (HookName) {
  267. HookName["beforeAll"] = "beforeAll";
  268. HookName["beforeEach"] = "beforeEach";
  269. HookName["afterAll"] = "afterAll";
  270. HookName["afterEach"] = "afterEach";
  271. })(HookName || (exports.HookName = HookName = {}));
  272. let DescribeProperty;
  273. exports.DescribeProperty = DescribeProperty;
  274. (function (DescribeProperty) {
  275. DescribeProperty["each"] = "each";
  276. DescribeProperty["only"] = "only";
  277. DescribeProperty["skip"] = "skip";
  278. })(DescribeProperty || (exports.DescribeProperty = DescribeProperty = {}));
  279. let TestCaseProperty;
  280. exports.TestCaseProperty = TestCaseProperty;
  281. (function (TestCaseProperty) {
  282. TestCaseProperty["each"] = "each";
  283. TestCaseProperty["concurrent"] = "concurrent";
  284. TestCaseProperty["only"] = "only";
  285. TestCaseProperty["skip"] = "skip";
  286. TestCaseProperty["todo"] = "todo";
  287. })(TestCaseProperty || (exports.TestCaseProperty = TestCaseProperty = {}));
  288. const joinNames = (a, b) => a && b ? `${a}.${b}` : null;
  289. function getNodeName(node) {
  290. if (isSupportedAccessor(node)) {
  291. return getAccessorValue(node);
  292. }
  293. switch (node.type) {
  294. case _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression:
  295. return getNodeName(node.tag);
  296. case _experimentalUtils.AST_NODE_TYPES.MemberExpression:
  297. return joinNames(getNodeName(node.object), getNodeName(node.property));
  298. case _experimentalUtils.AST_NODE_TYPES.NewExpression:
  299. case _experimentalUtils.AST_NODE_TYPES.CallExpression:
  300. return getNodeName(node.callee);
  301. }
  302. return null;
  303. }
  304. const isFunction = node => node.type === _experimentalUtils.AST_NODE_TYPES.FunctionExpression || node.type === _experimentalUtils.AST_NODE_TYPES.ArrowFunctionExpression;
  305. exports.isFunction = isFunction;
  306. const isHook = node => node.callee.type === _experimentalUtils.AST_NODE_TYPES.Identifier && HookName.hasOwnProperty(node.callee.name);
  307. exports.isHook = isHook;
  308. const getTestCallExpressionsFromDeclaredVariables = declaredVariables => {
  309. return declaredVariables.reduce((acc, {
  310. references
  311. }) => acc.concat(references.map(({
  312. identifier
  313. }) => identifier.parent).filter(node => !!node && node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && isTestCaseCall(node))), []);
  314. };
  315. exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables;
  316. const isTestCaseName = node => node.type === _experimentalUtils.AST_NODE_TYPES.Identifier && TestCaseName.hasOwnProperty(node.name);
  317. const isTestCaseProperty = node => isSupportedAccessor(node) && TestCaseProperty.hasOwnProperty(getAccessorValue(node));
  318. /**
  319. * Checks if the given `node` is a *call* to a test case function that would
  320. * result in tests being run by `jest`.
  321. *
  322. * Note that `.each()` does not count as a call in this context, as it will not
  323. * result in `jest` running any tests.
  324. *
  325. * @param {TSESTree.CallExpression} node
  326. *
  327. * @return {node is JestFunctionCallExpression<TestCaseName>}
  328. */
  329. const isTestCaseCall = node => {
  330. if (isTestCaseName(node.callee)) {
  331. return true;
  332. }
  333. const callee = node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _experimentalUtils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee;
  334. if (callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && isTestCaseProperty(callee.property)) {
  335. // if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`)
  336. if (getAccessorValue(callee.property) === 'each' && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
  337. return false;
  338. }
  339. return callee.object.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression ? isTestCaseName(callee.object.object) : isTestCaseName(callee.object);
  340. }
  341. return false;
  342. };
  343. exports.isTestCaseCall = isTestCaseCall;
  344. const isDescribeAlias = node => node.type === _experimentalUtils.AST_NODE_TYPES.Identifier && DescribeAlias.hasOwnProperty(node.name);
  345. const isDescribeProperty = node => isSupportedAccessor(node) && DescribeProperty.hasOwnProperty(getAccessorValue(node));
  346. /**
  347. * Checks if the given `node` is a *call* to a `describe` function that would
  348. * result in a `describe` block being created by `jest`.
  349. *
  350. * Note that `.each()` does not count as a call in this context, as it will not
  351. * result in `jest` creating any `describe` blocks.
  352. *
  353. * @param {TSESTree.CallExpression} node
  354. *
  355. * @return {node is JestFunctionCallExpression<TestCaseName>}
  356. */
  357. const isDescribeCall = node => {
  358. if (isDescribeAlias(node.callee)) {
  359. return true;
  360. }
  361. const callee = node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _experimentalUtils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee;
  362. if (callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && isDescribeProperty(callee.property)) {
  363. // if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`)
  364. if (getAccessorValue(callee.property) === 'each' && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
  365. return false;
  366. }
  367. return callee.object.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression ? isDescribeAlias(callee.object.object) : isDescribeAlias(callee.object);
  368. }
  369. return false;
  370. };
  371. exports.isDescribeCall = isDescribeCall;
  372. const collectReferences = scope => {
  373. const locals = new Set();
  374. const unresolved = new Set();
  375. let currentScope = scope;
  376. while (currentScope !== null) {
  377. for (const ref of currentScope.variables) {
  378. const isReferenceDefined = ref.defs.some(def => {
  379. return def.type !== 'ImplicitGlobalVariable';
  380. });
  381. if (isReferenceDefined) {
  382. locals.add(ref.name);
  383. }
  384. }
  385. for (const ref of currentScope.through) {
  386. unresolved.add(ref.identifier.name);
  387. }
  388. currentScope = currentScope.upper;
  389. }
  390. return {
  391. locals,
  392. unresolved
  393. };
  394. };
  395. const scopeHasLocalReference = (scope, referenceName) => {
  396. const references = collectReferences(scope);
  397. return (// referenceName was found as a local variable or function declaration.
  398. references.locals.has(referenceName) || // referenceName was not found as an unresolved reference,
  399. // meaning it is likely not an implicit global reference.
  400. !references.unresolved.has(referenceName)
  401. );
  402. };
  403. exports.scopeHasLocalReference = scopeHasLocalReference;