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.

eslint-plugin-prettier.js 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /**
  2. * @fileoverview Runs `prettier` as an ESLint rule.
  3. * @author Andres Suarez
  4. */
  5. 'use strict';
  6. // ------------------------------------------------------------------------------
  7. // Requirements
  8. // ------------------------------------------------------------------------------
  9. const {
  10. showInvisibles,
  11. generateDifferences,
  12. } = require('prettier-linter-helpers');
  13. // ------------------------------------------------------------------------------
  14. // Constants
  15. // ------------------------------------------------------------------------------
  16. const { INSERT, DELETE, REPLACE } = generateDifferences;
  17. // ------------------------------------------------------------------------------
  18. // Privates
  19. // ------------------------------------------------------------------------------
  20. // Lazily-loaded Prettier.
  21. /**
  22. * @type {import('prettier')}
  23. */
  24. let prettier;
  25. // ------------------------------------------------------------------------------
  26. // Rule Definition
  27. // ------------------------------------------------------------------------------
  28. /**
  29. * Reports a difference.
  30. * @param {import('eslint').Rule.RuleContext} context - The ESLint rule context.
  31. * @param {import('prettier-linter-helpers').Difference} difference - The difference object.
  32. * @returns {void}
  33. */
  34. function reportDifference(context, difference) {
  35. const { operation, offset, deleteText = '', insertText = '' } = difference;
  36. const range = [offset, offset + deleteText.length];
  37. const [start, end] = range.map((index) =>
  38. context.getSourceCode().getLocFromIndex(index)
  39. );
  40. context.report({
  41. messageId: operation,
  42. data: {
  43. deleteText: showInvisibles(deleteText),
  44. insertText: showInvisibles(insertText),
  45. },
  46. loc: { start, end },
  47. fix: (fixer) => fixer.replaceTextRange(range, insertText),
  48. });
  49. }
  50. // ------------------------------------------------------------------------------
  51. // Module Definition
  52. // ------------------------------------------------------------------------------
  53. module.exports = {
  54. configs: {
  55. recommended: {
  56. extends: ['prettier'],
  57. plugins: ['prettier'],
  58. rules: {
  59. 'prettier/prettier': 'error',
  60. 'arrow-body-style': 'off',
  61. 'prefer-arrow-callback': 'off',
  62. },
  63. },
  64. },
  65. rules: {
  66. prettier: {
  67. meta: {
  68. docs: {
  69. url: 'https://github.com/prettier/eslint-plugin-prettier#options',
  70. },
  71. type: 'layout',
  72. fixable: 'code',
  73. schema: [
  74. // Prettier options:
  75. {
  76. type: 'object',
  77. properties: {},
  78. additionalProperties: true,
  79. },
  80. {
  81. type: 'object',
  82. properties: {
  83. usePrettierrc: { type: 'boolean' },
  84. fileInfoOptions: {
  85. type: 'object',
  86. properties: {},
  87. additionalProperties: true,
  88. },
  89. },
  90. additionalProperties: true,
  91. },
  92. ],
  93. messages: {
  94. [INSERT]: 'Insert `{{ insertText }}`',
  95. [DELETE]: 'Delete `{{ deleteText }}`',
  96. [REPLACE]: 'Replace `{{ deleteText }}` with `{{ insertText }}`',
  97. },
  98. },
  99. create(context) {
  100. const usePrettierrc =
  101. !context.options[1] || context.options[1].usePrettierrc !== false;
  102. const eslintFileInfoOptions =
  103. (context.options[1] && context.options[1].fileInfoOptions) || {};
  104. const sourceCode = context.getSourceCode();
  105. const filepath = context.getFilename();
  106. // Processors that extract content from a file, such as the markdown
  107. // plugin extracting fenced code blocks may choose to specify virtual
  108. // file paths. If this is the case then we need to resolve prettier
  109. // config and file info using the on-disk path instead of the virtual
  110. // path.
  111. const onDiskFilepath = context.getPhysicalFilename();
  112. const source = sourceCode.text;
  113. return {
  114. Program() {
  115. if (!prettier) {
  116. // Prettier is expensive to load, so only load it if needed.
  117. prettier = require('prettier');
  118. }
  119. const eslintPrettierOptions = context.options[0] || {};
  120. const prettierRcOptions = usePrettierrc
  121. ? prettier.resolveConfig.sync(onDiskFilepath, {
  122. editorconfig: true,
  123. })
  124. : null;
  125. const { ignored, inferredParser } = prettier.getFileInfo.sync(
  126. onDiskFilepath,
  127. Object.assign(
  128. {},
  129. { resolveConfig: true, ignorePath: '.prettierignore' },
  130. eslintFileInfoOptions
  131. )
  132. );
  133. // Skip if file is ignored using a .prettierignore file
  134. if (ignored) {
  135. return;
  136. }
  137. const initialOptions = {};
  138. // ESLint supports processors that let you extract and lint JS
  139. // fragments within a non-JS language. In the cases where prettier
  140. // supports the same language as a processor, we want to process
  141. // the provided source code as javascript (as ESLint provides the
  142. // rules with fragments of JS) instead of guessing the parser
  143. // based off the filename. Otherwise, for instance, on a .md file we
  144. // end up trying to run prettier over a fragment of JS using the
  145. // markdown parser, which throws an error.
  146. // Processors may set virtual filenames for these extracted blocks.
  147. // If they do so then we want to trust the file extension they
  148. // provide, and no override is needed.
  149. // If the processor does not set any virtual filename (signified by
  150. // `filepath` and `onDiskFilepath` being equal) AND we can't
  151. // infer the parser from the filename, either because no filename
  152. // was provided or because there is no parser found for the
  153. // filename, use javascript.
  154. // This is added to the options first, so that
  155. // prettierRcOptions and eslintPrettierOptions can still override
  156. // the parser.
  157. //
  158. // `parserBlocklist` should contain the list of prettier parser
  159. // names for file types where:
  160. // * Prettier supports parsing the file type
  161. // * There is an ESLint processor that extracts JavaScript snippets
  162. // from the file type.
  163. const parserBlocklist = [null, 'markdown', 'html'];
  164. let inferParserToBabel =
  165. parserBlocklist.indexOf(inferredParser) !== -1;
  166. if (
  167. // it could be processed by `@graphql-eslint/eslint-plugin` or `eslint-plugin-graphql`
  168. inferredParser === 'graphql' &&
  169. // for `eslint-plugin-graphql`, see https://github.com/apollographql/eslint-plugin-graphql/blob/master/src/index.js#L416
  170. source.startsWith('ESLintPluginGraphQLFile`')
  171. ) {
  172. inferParserToBabel = true;
  173. }
  174. if (filepath === onDiskFilepath && inferParserToBabel) {
  175. initialOptions.parser = 'babel';
  176. }
  177. const prettierOptions = Object.assign(
  178. {},
  179. initialOptions,
  180. prettierRcOptions,
  181. eslintPrettierOptions,
  182. { filepath }
  183. );
  184. // prettier.format() may throw a SyntaxError if it cannot parse the
  185. // source code it is given. Usually for JS files this isn't a
  186. // problem as ESLint will report invalid syntax before trying to
  187. // pass it to the prettier plugin. However this might be a problem
  188. // for non-JS languages that are handled by a plugin. Notably Vue
  189. // files throw an error if they contain unclosed elements, such as
  190. // `<template><div></template>. In this case report an error at the
  191. // point at which parsing failed.
  192. let prettierSource;
  193. try {
  194. prettierSource = prettier.format(source, prettierOptions);
  195. } catch (err) {
  196. if (!(err instanceof SyntaxError)) {
  197. throw err;
  198. }
  199. let message = 'Parsing error: ' + err.message;
  200. // Prettier's message contains a codeframe style preview of the
  201. // invalid code and the line/column at which the error occurred.
  202. // ESLint shows those pieces of information elsewhere already so
  203. // remove them from the message
  204. if (err.codeFrame) {
  205. message = message.replace(`\n${err.codeFrame}`, '');
  206. }
  207. if (err.loc) {
  208. message = message.replace(/ \(\d+:\d+\)$/, '');
  209. }
  210. context.report({ message, loc: err.loc });
  211. return;
  212. }
  213. if (source !== prettierSource) {
  214. const differences = generateDifferences(source, prettierSource);
  215. for (const difference of differences) {
  216. reportDifference(context, difference);
  217. }
  218. }
  219. },
  220. };
  221. },
  222. },
  223. },
  224. };