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 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // @ts-nocheck
  2. 'use strict';
  3. const _ = require('lodash');
  4. const atRuleParamIndex = require('../../utils/atRuleParamIndex');
  5. const declarationValueIndex = require('../../utils/declarationValueIndex');
  6. const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
  7. const parseSelector = require('../../utils/parseSelector');
  8. const report = require('../../utils/report');
  9. const ruleMessages = require('../../utils/ruleMessages');
  10. const validateOptions = require('../../utils/validateOptions');
  11. const valueParser = require('postcss-value-parser');
  12. const ruleName = 'string-quotes';
  13. const messages = ruleMessages(ruleName, {
  14. expected: (q) => `Expected ${q} quotes`,
  15. });
  16. const singleQuote = `'`;
  17. const doubleQuote = `"`;
  18. function rule(expectation, secondary, context) {
  19. const correctQuote = expectation === 'single' ? singleQuote : doubleQuote;
  20. const erroneousQuote = expectation === 'single' ? doubleQuote : singleQuote;
  21. return (root, result) => {
  22. const validOptions = validateOptions(
  23. result,
  24. ruleName,
  25. {
  26. actual: expectation,
  27. possible: ['single', 'double'],
  28. },
  29. {
  30. actual: secondary,
  31. possible: {
  32. avoidEscape: _.isBoolean,
  33. },
  34. optional: true,
  35. },
  36. );
  37. if (!validOptions) {
  38. return;
  39. }
  40. const avoidEscape = _.get(secondary, 'avoidEscape', true);
  41. root.walk((node) => {
  42. switch (node.type) {
  43. case 'atrule':
  44. checkDeclOrAtRule(node, node.params, atRuleParamIndex);
  45. break;
  46. case 'decl':
  47. checkDeclOrAtRule(node, node.value, declarationValueIndex);
  48. break;
  49. case 'rule':
  50. checkRule(node);
  51. break;
  52. }
  53. });
  54. function checkRule(ruleNode) {
  55. if (!isStandardSyntaxRule(ruleNode)) {
  56. return;
  57. }
  58. if (!ruleNode.selector.includes('[') || !ruleNode.selector.includes('=')) {
  59. return;
  60. }
  61. const fixPositions = [];
  62. parseSelector(ruleNode.selector, result, ruleNode, (selectorTree) => {
  63. let selectorFixed = false;
  64. selectorTree.walkAttributes((attributeNode) => {
  65. if (!attributeNode.quoted) {
  66. return;
  67. }
  68. if (attributeNode.quoteMark === correctQuote) {
  69. if (avoidEscape) {
  70. const needsCorrectEscape = attributeNode.value.includes(correctQuote);
  71. const needsOtherEscape = attributeNode.value.includes(erroneousQuote);
  72. if (needsOtherEscape) {
  73. return;
  74. }
  75. if (needsCorrectEscape) {
  76. if (context.fix) {
  77. selectorFixed = true;
  78. attributeNode.quoteMark = erroneousQuote;
  79. } else {
  80. report({
  81. message: messages.expected(expectation === 'single' ? 'double' : expectation),
  82. node: ruleNode,
  83. index: attributeNode.sourceIndex + attributeNode.offsetOf('value'),
  84. result,
  85. ruleName,
  86. });
  87. }
  88. }
  89. }
  90. }
  91. if (attributeNode.quoteMark === erroneousQuote) {
  92. if (avoidEscape) {
  93. const needsCorrectEscape = attributeNode.value.includes(correctQuote);
  94. const needsOtherEscape = attributeNode.value.includes(erroneousQuote);
  95. if (needsOtherEscape) {
  96. if (context.fix) {
  97. selectorFixed = true;
  98. attributeNode.quoteMark = correctQuote;
  99. } else {
  100. report({
  101. message: messages.expected(expectation),
  102. node: ruleNode,
  103. index: attributeNode.sourceIndex + attributeNode.offsetOf('value'),
  104. result,
  105. ruleName,
  106. });
  107. }
  108. return;
  109. }
  110. if (needsCorrectEscape) {
  111. return;
  112. }
  113. }
  114. if (context.fix) {
  115. selectorFixed = true;
  116. attributeNode.quoteMark = correctQuote;
  117. } else {
  118. report({
  119. message: messages.expected(expectation),
  120. node: ruleNode,
  121. index: attributeNode.sourceIndex + attributeNode.offsetOf('value'),
  122. result,
  123. ruleName,
  124. });
  125. }
  126. }
  127. });
  128. if (selectorFixed) {
  129. ruleNode.selector = selectorTree.toString();
  130. }
  131. });
  132. fixPositions.forEach((fixIndex) => {
  133. ruleNode.selector = replaceQuote(ruleNode.selector, fixIndex, correctQuote);
  134. });
  135. }
  136. function checkDeclOrAtRule(node, value, getIndex) {
  137. const fixPositions = [];
  138. // Get out quickly if there are no erroneous quotes
  139. if (!value.includes(erroneousQuote)) {
  140. return;
  141. }
  142. if (node.type === 'atrule' && node.name === 'charset') {
  143. // allow @charset rules to have double quotes, in spite of the configuration
  144. // TODO: @charset should always use double-quotes, see https://github.com/stylelint/stylelint/issues/2788
  145. return;
  146. }
  147. valueParser(value).walk((valueNode) => {
  148. if (valueNode.type === 'string' && valueNode.quote === erroneousQuote) {
  149. const needsEscape = valueNode.value.includes(correctQuote);
  150. if (avoidEscape && needsEscape) {
  151. // don't consider this an error
  152. return;
  153. }
  154. const openIndex = valueNode.sourceIndex;
  155. // we currently don't fix escapes
  156. if (context.fix && !needsEscape) {
  157. const closeIndex = openIndex + valueNode.value.length + erroneousQuote.length;
  158. fixPositions.push(openIndex, closeIndex);
  159. } else {
  160. report({
  161. message: messages.expected(expectation),
  162. node,
  163. index: getIndex(node) + openIndex,
  164. result,
  165. ruleName,
  166. });
  167. }
  168. }
  169. });
  170. fixPositions.forEach((fixIndex) => {
  171. if (node.type === 'atrule') {
  172. node.params = replaceQuote(node.params, fixIndex, correctQuote);
  173. } else {
  174. node.value = replaceQuote(node.value, fixIndex, correctQuote);
  175. }
  176. });
  177. }
  178. };
  179. }
  180. function replaceQuote(string, index, replace) {
  181. return string.substring(0, index) + replace + string.substring(index + replace.length);
  182. }
  183. rule.ruleName = ruleName;
  184. rule.messages = messages;
  185. module.exports = rule;