no-unpublished-bin.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * @author Toru Nagashima
  3. * @copyright 2016 Toru Nagashima. All rights reserved.
  4. * See LICENSE file in root directory for full license.
  5. */
  6. "use strict"
  7. //------------------------------------------------------------------------------
  8. // Requirements
  9. //------------------------------------------------------------------------------
  10. const path = require("path")
  11. const getConvertPath = require("../util/get-convert-path")
  12. const getDocsUrl = require("../util/get-docs-url")
  13. const getNpmignore = require("../util/get-npmignore")
  14. const getPackageJson = require("../util/get-package-json")
  15. //------------------------------------------------------------------------------
  16. // Helpers
  17. //------------------------------------------------------------------------------
  18. /**
  19. * Checks whether or not a given path is a `bin` file.
  20. *
  21. * @param {string} filePath - A file path to check.
  22. * @param {string|object|undefined} binField - A value of the `bin` field of `package.json`.
  23. * @param {string} basedir - A directory path that `package.json` exists.
  24. * @returns {boolean} `true` if the file is a `bin` file.
  25. */
  26. function isBinFile(filePath, binField, basedir) {
  27. if (!binField) {
  28. return false
  29. }
  30. if (typeof binField === "string") {
  31. return filePath === path.resolve(basedir, binField)
  32. }
  33. return Object.keys(binField).some(key => filePath === path.resolve(basedir, binField[key]))
  34. }
  35. /**
  36. * The definition of this rule.
  37. *
  38. * @param {RuleContext} context - The rule context to check.
  39. * @returns {object} The definition of this rule.
  40. */
  41. function create(context) {
  42. return {
  43. Program(node) {
  44. // Check file path.
  45. let rawFilePath = context.getFilename()
  46. if (rawFilePath === "<input>") {
  47. return
  48. }
  49. rawFilePath = path.resolve(rawFilePath)
  50. // Find package.json
  51. const p = getPackageJson(rawFilePath)
  52. if (!p) {
  53. return
  54. }
  55. // Convert by convertPath option
  56. const basedir = path.dirname(p.filePath)
  57. const relativePath = getConvertPath(context)(
  58. path.relative(basedir, rawFilePath).replace(/\\/g, "/")
  59. )
  60. const filePath = path.join(basedir, relativePath)
  61. // Check this file is bin.
  62. if (!isBinFile(filePath, p.bin, basedir)) {
  63. return
  64. }
  65. // Check ignored or not
  66. const npmignore = getNpmignore(filePath)
  67. if (!npmignore.match(relativePath)) {
  68. return
  69. }
  70. // Report.
  71. context.report({
  72. node,
  73. message:
  74. "npm ignores '{{name}}'. " +
  75. "Check 'files' field of 'package.json' or '.npmignore'.",
  76. data: { name: relativePath },
  77. })
  78. },
  79. }
  80. }
  81. //------------------------------------------------------------------------------
  82. // Rule Definition
  83. //------------------------------------------------------------------------------
  84. module.exports = {
  85. create,
  86. meta: {
  87. docs: {
  88. description: "disallow 'bin' files which are ignored by npm",
  89. category: "Possible Errors",
  90. recommended: true,
  91. url: getDocsUrl("no-unpublished-bin.md"),
  92. },
  93. fixable: false,
  94. schema: [
  95. {
  96. type: "object",
  97. properties: { //
  98. convertPath: getConvertPath.schema,
  99. },
  100. },
  101. ],
  102. },
  103. }