project/lib/validation/validator.js

  1. const path = require("path");
  2. const {promisify} = require("util");
  3. const readFile = promisify(require("fs").readFile);
  4. async function loadSchema(schemaPath) {
  5. const filePath = schemaPath.replace("http://ui5.sap/schema/", "");
  6. const schemaFile = await readFile(path.join(__dirname, "schema", filePath), {encoding: "utf8"});
  7. return JSON.parse(schemaFile);
  8. }
  9. /**
  10. * @private
  11. * @memberof module:@ui5/project.validation
  12. */
  13. class Validator {
  14. constructor() {
  15. const Ajv = require("ajv");
  16. this.ajv = new Ajv({
  17. allErrors: true,
  18. jsonPointers: true,
  19. loadSchema
  20. });
  21. const ajvErrors = require("ajv-errors");
  22. ajvErrors(this.ajv);
  23. }
  24. _compileSchema() {
  25. if (!this._compiling) {
  26. this._compiling = Promise.resolve().then(async () => {
  27. const schema = await loadSchema("ui5.json");
  28. const validate = await this.ajv.compileAsync(schema);
  29. return validate;
  30. });
  31. }
  32. return this._compiling;
  33. }
  34. async validate({config, project, yaml}) {
  35. const fnValidate = await this._compileSchema();
  36. const valid = fnValidate(config);
  37. if (!valid) {
  38. const ValidationError = require("./ValidationError");
  39. throw new ValidationError({
  40. errors: fnValidate.errors,
  41. schema: fnValidate.schema,
  42. project,
  43. yaml
  44. });
  45. }
  46. }
  47. }
  48. let validator;
  49. /**
  50. * @public
  51. * @namespace
  52. * @alias module:@ui5/project.validation.validator
  53. */
  54. module.exports = {
  55. /**
  56. * Validates the given configuration.
  57. *
  58. * @param {object} options
  59. * @param {object} options.config UI5 Configuration to validate
  60. * @param {object} options.project Project information
  61. * @param {string} options.project.id ID of the project
  62. * @param {object} [options.yaml] YAML information
  63. * @param {string} options.yaml.path Path of the YAML file
  64. * @param {string} options.yaml.source Content of the YAML file
  65. * @param {number} [options.yaml.documentIndex=0] Document index in case the YAML file contains multiple documents
  66. * @throws {module:@ui5/project.validation.ValidationError}
  67. * Rejects with a {@link module:@ui5/project.validation.ValidationError ValidationError}
  68. * when the validation fails.
  69. * @returns {Promise<undefined>} Returns a Promise that resolves when the validation succeeds
  70. * @public
  71. */
  72. validate: async (options) => {
  73. if (!validator) {
  74. validator = new Validator();
  75. }
  76. await validator.validate(options);
  77. },
  78. _Validator: Validator // For testing only
  79. };