1. 1 : const Resolver = require("../settingResolver");
  2. 2 :
  3. 3 : /* eslint-disable class-methods-use-this, no-underscore-dangle, no-restricted-syntax */
  4. 4 : const types = Object.getOwnPropertyNames(Resolver.prototype).slice(1);
  5. 5 :
  6. 6 : /**
  7. 7 : * Schema constructor that creates schemas for use in Komada.
  8. 8 : * @type {Object}
  9. 9 : */
  10. 10 : class Schema {
  11. 11 :
  12. 12 : /**
  13. 13 : * Constructs our schema that we can add into.
  14. 14 : * @param {Object} [schema] An object containing key:value pairs
  15. 15 : */
  16. 16 : constructor(schema) {
  17. 17 : if (schema) {
  18. 18 : for (const [key, value] of Object.entries(schema)) {
  19. 19 : this[key] = value;
  20. 20 : }
  21. 21 : }
  22. 22 : }
  23. 23 :
  24. 24 : /**
  25. 25 : * All of the valid key types in Komada at the present moment.
  26. 26 : * @typedef {string} Types
  27. 27 : * @property {string} user
  28. 28 : * @property {string} channel
  29. 29 : * @property {string} textChannel
  30. 30 : * @property {string} voiceChannel
  31. 31 : * @property {string} guild
  32. 32 : * @property {string} role
  33. 33 : * @property {string} boolean
  34. 34 : * @property {string} string
  35. 35 : * @property {string} integer
  36. 36 : * @property {string} float
  37. 37 : * @property {string} url
  38. 38 : * @property {string} command
  39. 39 : * @memberof Schema
  40. 40 : */
  41. 41 :
  42. 42 : /**
  43. 43 : * @typedef {object} Options
  44. 44 : * @property {Schema.Types} type The type of key you want to add
  45. 45 : * @property {?} value The default value to set the key to.
  46. 46 : * @property {number} min The minimum number, used for determining string length and amount for number types.
  47. 47 : * @property {number} max The maximum number, used for determining string length and amount for number types.
  48. 48 : * @property {boolean} Array A boolean indicating whether or not this key should be created and stored as an array.
  49. 49 : * @memberof Schema
  50. 50 : */
  51. 51 :
  52. 52 : /**
  53. 53 : * Add function that adds a new key into the schema. Only requires that you pass a name and type for the key.
  54. 54 : * @param {string} name The name of the key you want to add.
  55. 55 : * @param {Schema.Options} [options] An object containing extra options for a key.
  56. 56 : * @returns {Schema} Returns the schema you are creating so you can chain add calls.
  57. 57 : */
  58. 58 : add(name, { type, value, min, max, array } = {}) {
  59. 59 : [name, value, min, max, array, type] = this._validateInput(name, value, min, max, array, type.toLowerCase());
  60. 60 : if (["float", "integer", "string"].includes(type)) {
  61. 61 : this[name] = { type, default: value, min, max, array };
  62. 62 : return this;
  63. 63 : }
  64. 64 : this[name] = { type, default: value, array };
  65. 65 : return this;
  66. 66 : }
  67. 67 :
  68. 68 : /**
  69. 69 : * Returns an object containing the keys mapped to their default values.
  70. 70 : * @return {Object}
  71. 71 : */
  72. 72 : get defaults() {
  73. 73 : const defaults = {};
  74. 74 : for (const key of Object.keys(this)) {
  75. 75 : defaults[key] = this[key].default;
  76. 76 : }
  77. 77 : return defaults;
  78. 78 : }
  79. 79 :
  80. 80 : _validateInput(name, value, min, max, array, type) {
  81. 81 : if (!name) throw "You must provide a name for this new key.";
  82. 82 : if (!types.includes(type)) throw `Invalid type provided. Valid types are: ${types.join(", ")}`;
  83. 83 : if (array) {
  84. 84 : if (array.constructor.name !== "Boolean") throw "The array parameter must be a boolean.";
  85. 85 : value = value || [];
  86. 86 : if (!Array.isArray(value)) throw "The default value must be an array if you set array to true.";
  87. 87 : } else {
  88. 88 : array = false;
  89. 89 : value = value || null;
  90. 90 : }
  91. 91 : if (min || max) [min, max] = this._minOrMax(value, min, max);
  92. 92 : return [name, value, min, max, array, type];
  93. 93 : }
  94. 94 :
  95. 95 : _minOrMax(value, min, max) {
  96. 96 : if (!value) return [min, max];
  97. 97 : if (!Number.isNaN(min) && !Number.isNaN(max)) {
  98. 98 : if (value >= min && value <= max) return [min, max];
  99. 99 : if (min === max) throw `Value must be exactly ${min}`;
  100. 100 : throw `Value must be between ${min} and ${max}`;
  101. 101 : } else if (!Number.isNaN(min)) {
  102. 102 : if (value >= min) return [min, null];
  103. 103 : throw `Value must be longer than ${min}`;
  104. 104 : } else if (!Number.isNaN(max)) {
  105. 105 : if (value <= max) return [null, max];
  106. 106 : throw `Value must be shorter than ${max}`;
  107. 107 : }
  108. 108 : return [null, null];
  109. 109 : }
  110. 110 :
  111. 111 : }
  112. 112 :
  113. 113 : module.exports = Schema;