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.

rule-validator.js 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /**
  2. * @fileoverview Rule Validator
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //-----------------------------------------------------------------------------
  7. // Requirements
  8. //-----------------------------------------------------------------------------
  9. const ajv = require("../shared/ajv")();
  10. //-----------------------------------------------------------------------------
  11. // Helpers
  12. //-----------------------------------------------------------------------------
  13. /**
  14. * Finds a rule with the given ID in the given config.
  15. * @param {string} ruleId The ID of the rule to find.
  16. * @param {Object} config The config to search in.
  17. * @returns {{create: Function, schema: (Array|null)}} THe rule object.
  18. */
  19. function findRuleDefinition(ruleId, config) {
  20. const ruleIdParts = ruleId.split("/");
  21. let pluginName, ruleName;
  22. // built-in rule
  23. if (ruleIdParts.length === 1) {
  24. pluginName = "@";
  25. ruleName = ruleIdParts[0];
  26. } else {
  27. ruleName = ruleIdParts.pop();
  28. pluginName = ruleIdParts.join("/");
  29. }
  30. if (!config.plugins || !config.plugins[pluginName]) {
  31. throw new TypeError(`Key "rules": Key "${ruleId}": Could not find plugin "${pluginName}".`);
  32. }
  33. if (!config.plugins[pluginName].rules || !config.plugins[pluginName].rules[ruleName]) {
  34. throw new TypeError(`Key "rules": Key "${ruleId}": Could not find "${ruleName}" in plugin "${pluginName}".`);
  35. }
  36. return config.plugins[pluginName].rules[ruleName];
  37. }
  38. /**
  39. * Gets a complete options schema for a rule.
  40. * @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
  41. * @returns {Object} JSON Schema for the rule's options.
  42. */
  43. function getRuleOptionsSchema(rule) {
  44. if (!rule) {
  45. return null;
  46. }
  47. const schema = rule.schema || rule.meta && rule.meta.schema;
  48. if (Array.isArray(schema)) {
  49. if (schema.length) {
  50. return {
  51. type: "array",
  52. items: schema,
  53. minItems: 0,
  54. maxItems: schema.length
  55. };
  56. }
  57. return {
  58. type: "array",
  59. minItems: 0,
  60. maxItems: 0
  61. };
  62. }
  63. // Given a full schema, leave it alone
  64. return schema || null;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Exports
  68. //-----------------------------------------------------------------------------
  69. /**
  70. * Implements validation functionality for the rules portion of a config.
  71. */
  72. class RuleValidator {
  73. /**
  74. * Creates a new instance.
  75. */
  76. constructor() {
  77. /**
  78. * A collection of compiled validators for rules that have already
  79. * been validated.
  80. * @type {WeakMap}
  81. * @property validators
  82. */
  83. this.validators = new WeakMap();
  84. }
  85. /**
  86. * Validates all of the rule configurations in a config against each
  87. * rule's schema.
  88. * @param {Object} config The full config to validate. This object must
  89. * contain both the rules section and the plugins section.
  90. * @returns {void}
  91. * @throws {Error} If a rule's configuration does not match its schema.
  92. */
  93. validate(config) {
  94. if (!config.rules) {
  95. return;
  96. }
  97. for (const [ruleId, ruleOptions] of Object.entries(config.rules)) {
  98. // check for edge case
  99. if (ruleId === "__proto__") {
  100. continue;
  101. }
  102. /*
  103. * If a rule is disabled, we don't do any validation. This allows
  104. * users to safely set any value to 0 or "off" without worrying
  105. * that it will cause a validation error.
  106. *
  107. * Note: ruleOptions is always an array at this point because
  108. * this validation occurs after FlatConfigArray has merged and
  109. * normalized values.
  110. */
  111. if (ruleOptions[0] === 0) {
  112. continue;
  113. }
  114. const rule = findRuleDefinition(ruleId, config);
  115. // Precompile and cache validator the first time
  116. if (!this.validators.has(rule)) {
  117. const schema = getRuleOptionsSchema(rule);
  118. if (schema) {
  119. this.validators.set(rule, ajv.compile(schema));
  120. }
  121. }
  122. const validateRule = this.validators.get(rule);
  123. if (validateRule) {
  124. validateRule(ruleOptions.slice(1));
  125. if (validateRule.errors) {
  126. throw new Error(`Key "rules": Key "${ruleId}": ${
  127. validateRule.errors.map(
  128. error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
  129. ).join("")
  130. }`);
  131. }
  132. }
  133. }
  134. }
  135. }
  136. exports.RuleValidator = RuleValidator;