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.

index.js 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // @ts-nocheck
  2. 'use strict';
  3. const declarationValueIndex = require('../../utils/declarationValueIndex');
  4. const isStandardSyntaxMathFunction = require('../../utils/isStandardSyntaxMathFunction');
  5. const parseCalcExpression = require('../../utils/parseCalcExpression');
  6. const report = require('../../utils/report');
  7. const ruleMessages = require('../../utils/ruleMessages');
  8. const validateOptions = require('../../utils/validateOptions');
  9. const valueParser = require('postcss-value-parser');
  10. const ruleName = 'function-calc-no-invalid';
  11. const messages = ruleMessages(ruleName, {
  12. expectedExpression: () => 'Expected a valid expression',
  13. expectedSpaceBeforeOperator: (operator) => `Expected space before "${operator}" operator`,
  14. expectedSpaceAfterOperator: (operator) => `Expected space after "${operator}" operator`,
  15. rejectedDivisionByZero: () => 'Unexpected division by zero',
  16. expectedValidResolvedType: (operator) =>
  17. `Expected to be compatible with the left and right argument types of "${operator}" operation.`,
  18. });
  19. function rule(actual) {
  20. return (root, result) => {
  21. const validOptions = validateOptions(result, ruleName, { actual });
  22. if (!validOptions) {
  23. return;
  24. }
  25. root.walkDecls((decl) => {
  26. const checked = [];
  27. valueParser(decl.value).walk((node) => {
  28. if (node.type !== 'function' || node.value.toLowerCase() !== 'calc') {
  29. return;
  30. }
  31. const mathFunction = valueParser.stringify(node);
  32. if (!isStandardSyntaxMathFunction(mathFunction)) {
  33. return;
  34. }
  35. if (checked.includes(node)) {
  36. return;
  37. }
  38. checked.push(...getCalcNodes(node));
  39. checked.push(...node.nodes);
  40. let ast;
  41. try {
  42. ast = parseCalcExpression(mathFunction);
  43. } catch (e) {
  44. if (e.hash && e.hash.loc) {
  45. complain(messages.expectedExpression(), node.sourceIndex + e.hash.loc.range[0]);
  46. return;
  47. }
  48. throw e;
  49. }
  50. verifyMathExpressions(ast, node);
  51. });
  52. function complain(message, valueIndex) {
  53. report({
  54. message,
  55. node: decl,
  56. index: declarationValueIndex(decl) + valueIndex,
  57. result,
  58. ruleName,
  59. });
  60. }
  61. /**
  62. * Verify that each operation expression is valid.
  63. * Reports when a invalid operation expression is found.
  64. * @param {object} expression expression node.
  65. * @param {object} node calc function node.
  66. * @returns {void}
  67. */
  68. function verifyMathExpressions(expression, node) {
  69. if (expression.type === 'MathExpression') {
  70. const { operator, left, right } = expression;
  71. if (operator === '+' || operator === '-') {
  72. if (expression.source.operator.end.index === right.source.start.index) {
  73. complain(
  74. messages.expectedSpaceAfterOperator(operator),
  75. node.sourceIndex + expression.source.operator.end.index,
  76. );
  77. }
  78. if (expression.source.operator.start.index === left.source.end.index) {
  79. complain(
  80. messages.expectedSpaceBeforeOperator(operator),
  81. node.sourceIndex + expression.source.operator.start.index,
  82. );
  83. }
  84. } else if (operator === '/') {
  85. if (
  86. (right.type === 'Value' && right.value === 0) ||
  87. (right.type === 'MathExpression' && getNumber(right) === 0)
  88. ) {
  89. complain(
  90. messages.rejectedDivisionByZero(),
  91. node.sourceIndex + expression.source.operator.end.index,
  92. );
  93. }
  94. }
  95. if (getResolvedType(expression) === 'invalid') {
  96. complain(
  97. messages.expectedValidResolvedType(operator),
  98. node.sourceIndex + expression.source.operator.start.index,
  99. );
  100. }
  101. verifyMathExpressions(expression.left, node);
  102. verifyMathExpressions(expression.right, node);
  103. }
  104. }
  105. });
  106. };
  107. }
  108. function getCalcNodes(node) {
  109. if (node.type !== 'function') {
  110. return [];
  111. }
  112. const functionName = node.value.toLowerCase();
  113. const result = [];
  114. if (functionName === 'calc') {
  115. result.push(node);
  116. }
  117. if (!functionName || functionName === 'calc') {
  118. // find nested calc
  119. for (const c of node.nodes) {
  120. result.push(...getCalcNodes(c));
  121. }
  122. }
  123. return result;
  124. }
  125. function getNumber(mathExpression) {
  126. const { left, right } = mathExpression;
  127. const leftValue =
  128. left.type === 'Value' ? left.value : left.type === 'MathExpression' ? getNumber(left) : null;
  129. const rightValue =
  130. right.type === 'Value'
  131. ? right.value
  132. : right.type === 'MathExpression'
  133. ? getNumber(right)
  134. : null;
  135. if (leftValue == null || rightValue == null) {
  136. return null;
  137. }
  138. switch (mathExpression.operator) {
  139. case '+':
  140. return leftValue + rightValue;
  141. case '-':
  142. return leftValue - rightValue;
  143. case '*':
  144. return leftValue * rightValue;
  145. case '/':
  146. return leftValue / rightValue;
  147. }
  148. return null;
  149. }
  150. function getResolvedType(mathExpression) {
  151. const { left: leftExpression, operator, right: rightExpression } = mathExpression;
  152. let left =
  153. leftExpression.type === 'MathExpression'
  154. ? getResolvedType(leftExpression)
  155. : leftExpression.type;
  156. let right =
  157. rightExpression.type === 'MathExpression'
  158. ? getResolvedType(rightExpression)
  159. : rightExpression.type;
  160. if (left === 'Function' || left === 'invalid') {
  161. left = 'UnknownValue';
  162. }
  163. if (right === 'Function' || right === 'invalid') {
  164. right = 'UnknownValue';
  165. }
  166. switch (operator) {
  167. case '+':
  168. case '-':
  169. if (left === 'UnknownValue' || right === 'UnknownValue') {
  170. return 'UnknownValue';
  171. }
  172. if (left === right) {
  173. return left;
  174. }
  175. if (left === 'Value' || right === 'Value') {
  176. return 'invalid';
  177. }
  178. if (left === 'PercentageValue') {
  179. return right;
  180. }
  181. if (right === 'PercentageValue') {
  182. return left;
  183. }
  184. return 'invalid';
  185. case '*':
  186. if (left === 'UnknownValue' || right === 'UnknownValue') {
  187. return 'UnknownValue';
  188. }
  189. if (left === 'Value') {
  190. return right;
  191. }
  192. if (right === 'Value') {
  193. return left;
  194. }
  195. return 'invalid';
  196. case '/':
  197. if (right === 'UnknownValue') {
  198. return 'UnknownValue';
  199. }
  200. if (right === 'Value') {
  201. return left;
  202. }
  203. return 'invalid';
  204. }
  205. return 'UnknownValue';
  206. }
  207. rule.ruleName = ruleName;
  208. rule.messages = messages;
  209. module.exports = rule;