项目原始demo,不改动
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 

220 lines
5.9 KiB

  1. "use strict"
  2. var assign = require("object-assign")
  3. var loaderUtils = require("loader-utils")
  4. var objectHash = require("object-hash")
  5. var pkg = require("./package.json")
  6. var createCache = require("loader-fs-cache")
  7. var cache = createCache("eslint-loader")
  8. var engines = {}
  9. /**
  10. * Class representing an ESLintError.
  11. * @extends Error
  12. */
  13. class ESLintError extends Error {
  14. /**
  15. * Create an ESLintError.
  16. * @param {string} messages - Formatted eslint errors.
  17. */
  18. constructor(messages) {
  19. super()
  20. this.name = "ESLintError"
  21. this.message = messages
  22. this.stack = ""
  23. }
  24. /**
  25. * Returns a stringified representation of our error. This method is called
  26. * when an error is consumed by console methods
  27. * ex: console.error(new ESLintError(formattedMessage))
  28. * @return {string} error - A stringified representation of the error.
  29. */
  30. inspect() {
  31. return this.message
  32. }
  33. }
  34. /**
  35. * printLinterOutput
  36. *
  37. * @param {Object} eslint.executeOnText return value
  38. * @param {Object} config eslint configuration
  39. * @param {Object} webpack webpack instance
  40. * @return {void}
  41. */
  42. function printLinterOutput(res, config, webpack) {
  43. // skip ignored file warning
  44. if (
  45. !(res.warningCount === 1 &&
  46. res.results[0].messages[0] &&
  47. res.results[0].messages[0].message &&
  48. res.results[0].messages[0].message.indexOf("ignore") > 1)
  49. ) {
  50. // quiet filter done now
  51. // eslint allow rules to be specified in the input between comments
  52. // so we can found warnings defined in the input itself
  53. if (res.warningCount && config.quiet) {
  54. res.warningCount = 0
  55. res.results[0].warningCount = 0
  56. res.results[0].messages = res.results[0].messages.filter(function(
  57. message
  58. ) {
  59. return message.severity !== 1
  60. })
  61. }
  62. // if enabled, use eslint auto-fixing where possible
  63. if (config.fix && res.results[0].output) {
  64. var eslint = require(config.eslintPath)
  65. eslint.CLIEngine.outputFixes(res)
  66. }
  67. if (res.errorCount || res.warningCount) {
  68. // add filename for each results so formatter can have relevant filename
  69. res.results.forEach(function(r) {
  70. r.filePath = webpack.resourcePath
  71. })
  72. var messages = config.formatter(res.results)
  73. if (config.outputReport && config.outputReport.filePath) {
  74. var reportOutput
  75. // if a different formatter is passed in as an option use that
  76. if (config.outputReport.formatter) {
  77. reportOutput = config.outputReport.formatter(res.results)
  78. }
  79. else {
  80. reportOutput = messages
  81. }
  82. var filePath = loaderUtils.interpolateName(webpack,
  83. config.outputReport.filePath, {
  84. content: res.results.map(function(r) {
  85. return r.source
  86. }).join("\n"),
  87. }
  88. )
  89. webpack.emitFile(filePath, reportOutput)
  90. }
  91. // default behavior: emit error only if we have errors
  92. var emitter = res.errorCount ? webpack.emitError : webpack.emitWarning
  93. // force emitError or emitWarning if user want this
  94. if (config.emitError) {
  95. emitter = webpack.emitError
  96. }
  97. else if (config.emitWarning) {
  98. emitter = webpack.emitWarning
  99. }
  100. if (emitter) {
  101. if (config.failOnError && res.errorCount) {
  102. throw new ESLintError(
  103. "Module failed because of a eslint error.\n" + messages
  104. )
  105. }
  106. else if (config.failOnWarning && res.warningCount) {
  107. throw new ESLintError(
  108. "Module failed because of a eslint warning.\n" + messages
  109. )
  110. }
  111. emitter(webpack.version === 2 ? new ESLintError(messages) : messages)
  112. }
  113. else {
  114. throw new Error(
  115. "Your module system doesn't support emitWarning. " +
  116. "Update available? \n" +
  117. messages
  118. )
  119. }
  120. }
  121. }
  122. }
  123. /**
  124. * webpack loader
  125. *
  126. * @param {String|Buffer} input JavaScript string
  127. * @param {Object} map input source map
  128. * @return {void}
  129. */
  130. module.exports = function(input, map) {
  131. var webpack = this
  132. var userOptions = assign(
  133. // user defaults
  134. this.options.eslint || {},
  135. // loader query string
  136. loaderUtils.getOptions(this)
  137. )
  138. var config = assign(
  139. // loader defaults
  140. {
  141. formatter: require("eslint/lib/formatters/stylish"),
  142. cacheIdentifier: JSON.stringify({
  143. "eslint-loader": pkg.version,
  144. eslint: require(userOptions.eslintPath || "eslint").version,
  145. }),
  146. eslintPath: "eslint",
  147. },
  148. userOptions
  149. )
  150. var cacheDirectory = config.cache
  151. var cacheIdentifier = config.cacheIdentifier
  152. delete config.cacheDirectory
  153. delete config.cacheIdentifier
  154. // Create the engine only once per config
  155. var configHash = objectHash(config)
  156. if (!engines[configHash]) {
  157. var eslint = require(config.eslintPath)
  158. engines[configHash] = new eslint.CLIEngine(config)
  159. }
  160. this.cacheable()
  161. var resourcePath = webpack.resourcePath
  162. var cwd = process.cwd()
  163. // remove cwd from resource path in case webpack has been started from project
  164. // root, to allow having relative paths in .eslintignore
  165. if (resourcePath.indexOf(cwd) === 0) {
  166. resourcePath = resourcePath.substr(cwd.length + 1)
  167. }
  168. var engine = engines[configHash]
  169. // return early if cached
  170. if (config.cache) {
  171. var callback = this.async()
  172. return cache(
  173. {
  174. directory: cacheDirectory,
  175. identifier: cacheIdentifier,
  176. options: config,
  177. source: input,
  178. transform: function() {
  179. return lint(engine, input, resourcePath)
  180. },
  181. },
  182. function(err, res) {
  183. if (err) {
  184. return callback(err)
  185. }
  186. printLinterOutput(res || {}, config, webpack)
  187. return callback(null, input, map)
  188. }
  189. )
  190. }
  191. printLinterOutput(lint(engine, input, resourcePath), config, this)
  192. this.callback(null, input, map)
  193. }
  194. function lint(engine, input, resourcePath) {
  195. return engine.executeOnText(input, resourcePath, true)
  196. }