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.

stylelint-prettier.js 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. const stylelint = require('stylelint');
  2. const {
  3. showInvisibles,
  4. generateDifferences,
  5. } = require('prettier-linter-helpers');
  6. const {INSERT, DELETE, REPLACE} = generateDifferences;
  7. let prettier;
  8. const ruleName = 'prettier/prettier';
  9. const messages = stylelint.utils.ruleMessages(ruleName, {
  10. insert: (code) => `Insert "${showInvisibles(code)}"`,
  11. delete: (code) => `Delete "${showInvisibles(code)}"`,
  12. replace: (deleteCode, insertCode) =>
  13. `Replace "${showInvisibles(deleteCode)}" with "${showInvisibles(
  14. insertCode
  15. )}"`,
  16. });
  17. module.exports = stylelint.createPlugin(
  18. ruleName,
  19. (expectation, options, context) => {
  20. return (root, result) => {
  21. const validOptions = stylelint.utils.validateOptions(result, ruleName, {
  22. actual: expectation,
  23. });
  24. if (!validOptions) {
  25. return;
  26. }
  27. // Stylelint can handle css-in-js, in which it formats object literals.
  28. // We don't want to run these extracts of JS through prettier
  29. if (root.source.lang === 'object-literal') {
  30. return;
  31. }
  32. const stylelintPrettierOptions = omitStylelintSpecificOptions(options);
  33. if (!prettier) {
  34. // Prettier is expensive to load, so only load it if needed.
  35. prettier = require('prettier');
  36. }
  37. // Default to '<input>' if a filepath was not provided.
  38. // This mimics eslint's behaviour
  39. const filepath = root.source.input.file || '<input>';
  40. const source = root.source.input.css;
  41. const prettierRcOptions =
  42. prettier.resolveConfig && prettier.resolveConfig.sync
  43. ? prettier.resolveConfig.sync(filepath, {editorconfig: true})
  44. : null;
  45. //prettier.getFileInfo was added in v1.13
  46. const prettierFileInfo =
  47. prettier.getFileInfo && prettier.getFileInfo.sync
  48. ? prettier.getFileInfo.sync(filepath, {
  49. resolveConfig: true,
  50. ignorePath: '.prettierignore',
  51. })
  52. : {ignored: false, inferredParser: null};
  53. // Skip if file is ignored using a .prettierignore file
  54. if (prettierFileInfo.ignored) {
  55. return;
  56. }
  57. const initialOptions = {};
  58. // If no filepath was provided then assume the CSS parser
  59. // This is added to the options first, so that
  60. // prettierRcOptions and stylelintPrettierOptions can still override
  61. // the parser.
  62. if (filepath == '<input>') {
  63. initialOptions.parser = 'css';
  64. }
  65. // Stylelint supports languages that may contain multiple types of style
  66. // languages, thus we can't rely on guessing the parser based off the
  67. // filename.
  68. // In all of the following cases stylelint extracts a part of a file to
  69. // be formatted and there exists a prettier parser for the whole file.
  70. // If you're interested in prettier you'll want a fully formatted file so
  71. // you're about to run prettier over the whole file anyway.
  72. // Therefore running prettier over just the style section is wasteful, so
  73. // skip it.
  74. const parserBlockList = [
  75. 'babel',
  76. 'flow',
  77. 'typescript',
  78. 'vue',
  79. 'markdown',
  80. 'html',
  81. 'angular', // .component.html files
  82. 'svelte',
  83. ];
  84. if (parserBlockList.indexOf(prettierFileInfo.inferredParser) !== -1) {
  85. return;
  86. }
  87. const prettierOptions = Object.assign(
  88. {},
  89. initialOptions,
  90. prettierRcOptions,
  91. stylelintPrettierOptions,
  92. {filepath}
  93. );
  94. try {
  95. prettierSource = prettier.format(source, prettierOptions);
  96. } catch (err) {
  97. if (!(err instanceof SyntaxError)) {
  98. throw err;
  99. }
  100. let message = 'Parsing error: ' + err.message;
  101. // Prettier's message contains a codeframe style preview of the
  102. // invalid code and the line/column at which the error occurred.
  103. // ESLint shows those pieces of information elsewhere already so
  104. // remove them from the message
  105. if (err.codeFrame) {
  106. message = message.replace(`\n${err.codeFrame}`, '');
  107. }
  108. if (err.loc) {
  109. message = message.replace(/ \(\d+:\d+\)$/, '');
  110. }
  111. stylelint.utils.report({
  112. ruleName,
  113. result,
  114. message,
  115. node: root,
  116. index: getIndexFromLoc(source, err.loc.start),
  117. });
  118. return;
  119. }
  120. // Everything is the same. Nothing to do here;
  121. if (source === prettierSource) {
  122. return;
  123. }
  124. // Otherwise let's generate some differences
  125. const differences = generateDifferences(source, prettierSource);
  126. const report = (message, index) => {
  127. return stylelint.utils.report({
  128. ruleName,
  129. result,
  130. message,
  131. node: root,
  132. index,
  133. });
  134. };
  135. if (context.fix) {
  136. // Fixes must be processed in reverse order, as an early delete shall
  137. // change the modification offsets for anything after it
  138. const rawData = differences.reverse().reduce((rawData, difference) => {
  139. let insertText = '';
  140. let deleteText = '';
  141. switch (difference.operation) {
  142. case INSERT:
  143. insertText = difference.insertText;
  144. break;
  145. case DELETE:
  146. deleteText = difference.deleteText;
  147. break;
  148. case REPLACE:
  149. insertText = difference.insertText;
  150. deleteText = difference.deleteText;
  151. break;
  152. }
  153. return (
  154. rawData.substring(0, difference.offset) +
  155. insertText +
  156. rawData.substring(difference.offset + deleteText.length)
  157. );
  158. }, root.source.input.css);
  159. // If root.source.syntax exists then it means stylelint had to use
  160. // postcss-syntax to guess the postcss parser that it should use based
  161. // upon the input filename.
  162. // In that case we want to use the parser that postcss-syntax picked.
  163. // Otherwise use the syntax parser that was provided in the options
  164. const syntax = root.source.syntax || result.opts.syntax;
  165. const newRoot = syntax.parse(rawData);
  166. // For reasons I don't really understand, when the original input does
  167. // not have a trailing newline, newRoot generates a trailing newline but
  168. // it does not get included in the output.
  169. // Cleaning the root raws (to remove any existing whitespace), then
  170. // adding the final new line into the root raws seems to fix this
  171. root.removeAll();
  172. root.cleanRaws();
  173. root.append(newRoot);
  174. // Use the EOL whitespace from the rawData, as it could be \n or \r\n
  175. const trailingWhitespace = rawData.match(/[\s\uFEFF\xA0]+$/);
  176. if (trailingWhitespace) {
  177. root.raws.after = trailingWhitespace[0];
  178. }
  179. return;
  180. }
  181. // Report in the the order the differences appear in the content
  182. differences.forEach((difference) => {
  183. switch (difference.operation) {
  184. case INSERT:
  185. report(messages.insert(difference.insertText), difference.offset);
  186. break;
  187. case DELETE:
  188. report(messages.delete(difference.deleteText), difference.offset);
  189. break;
  190. case REPLACE:
  191. report(
  192. messages.replace(difference.deleteText, difference.insertText),
  193. difference.offset
  194. );
  195. break;
  196. }
  197. });
  198. };
  199. }
  200. );
  201. function omitStylelintSpecificOptions(options) {
  202. const prettierOptions = Object.assign({}, options);
  203. delete prettierOptions.message;
  204. delete prettierOptions.severity;
  205. return prettierOptions;
  206. }
  207. function getIndexFromLoc(source, {line, column}) {
  208. function nthIndex(str, searchValue, n) {
  209. let i = -1;
  210. while (n-- && i++ < str.length) {
  211. i = str.indexOf(searchValue, i);
  212. if (i < 0) {
  213. break;
  214. }
  215. }
  216. return i;
  217. }
  218. if (line === 1) {
  219. return column - 1;
  220. }
  221. return nthIndex(source, '\n', line - 1) + column;
  222. }
  223. module.exports.ruleName = ruleName;
  224. module.exports.messages = messages;