naming.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * @fileoverview Common helpers for naming of plugins, formatters and configs
  3. */
  4. "use strict";
  5. const NAMESPACE_REGEX = /^@.*\//u;
  6. /**
  7. * Brings package name to correct format based on prefix
  8. * @param {string} name The name of the package.
  9. * @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
  10. * @returns {string} Normalized name of the package
  11. * @private
  12. */
  13. function normalizePackageName(name, prefix) {
  14. let normalizedName = name;
  15. /**
  16. * On Windows, name can come in with Windows slashes instead of Unix slashes.
  17. * Normalize to Unix first to avoid errors later on.
  18. * https://github.com/eslint/eslint/issues/5644
  19. */
  20. if (normalizedName.includes("\\")) {
  21. normalizedName = normalizedName.replace(/\\/gu, "/");
  22. }
  23. if (normalizedName.charAt(0) === "@") {
  24. /**
  25. * it's a scoped package
  26. * package name is the prefix, or just a username
  27. */
  28. const scopedPackageShortcutRegex = new RegExp(
  29. `^(@[^/]+)(?:/(?:${prefix})?)?$`,
  30. "u",
  31. ),
  32. scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
  33. if (scopedPackageShortcutRegex.test(normalizedName)) {
  34. normalizedName = normalizedName.replace(
  35. scopedPackageShortcutRegex,
  36. `$1/${prefix}`,
  37. );
  38. } else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
  39. /**
  40. * for scoped packages, insert the prefix after the first / unless
  41. * the path is already @scope/eslint or @scope/eslint-xxx-yyy
  42. */
  43. normalizedName = normalizedName.replace(
  44. /^@([^/]+)\/(.*)$/u,
  45. `@$1/${prefix}-$2`,
  46. );
  47. }
  48. } else if (!normalizedName.startsWith(`${prefix}-`)) {
  49. normalizedName = `${prefix}-${normalizedName}`;
  50. }
  51. return normalizedName;
  52. }
  53. /**
  54. * Removes the prefix from a fullname.
  55. * @param {string} fullname The term which may have the prefix.
  56. * @param {string} prefix The prefix to remove.
  57. * @returns {string} The term without prefix.
  58. */
  59. function getShorthandName(fullname, prefix) {
  60. if (fullname[0] === "@") {
  61. let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(
  62. fullname,
  63. );
  64. if (matchResult) {
  65. return matchResult[1];
  66. }
  67. matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(
  68. fullname,
  69. );
  70. if (matchResult) {
  71. return `${matchResult[1]}/${matchResult[2]}`;
  72. }
  73. } else if (fullname.startsWith(`${prefix}-`)) {
  74. return fullname.slice(prefix.length + 1);
  75. }
  76. return fullname;
  77. }
  78. /**
  79. * Gets the scope (namespace) of a term.
  80. * @param {string} term The term which may have the namespace.
  81. * @returns {string} The namespace of the term if it has one.
  82. */
  83. function getNamespaceFromTerm(term) {
  84. const match = term.match(NAMESPACE_REGEX);
  85. return match ? match[0] : "";
  86. }
  87. //------------------------------------------------------------------------------
  88. // Public Interface
  89. //------------------------------------------------------------------------------
  90. module.exports = {
  91. normalizePackageName,
  92. getShorthandName,
  93. getNamespaceFromTerm,
  94. };