hapijs / joi

The most powerful data validation library for JS
Other
20.96k stars 1.51k forks source link

extension object fails validation when used twice #2514

Open nlundquist opened 4 years ago

nlundquist commented 4 years ago

Context

What are you trying to achieve or the steps to reproduce?

Trying to pass an extension object instance (rather than a generator function) to Joi twice results in a validation error due to a modification made by Joi.

import joi from 'https://cdn.skypack.dev/joi@~17.3.0';

const extension = {
  type: 'foo',
  base: joi.string(),
  rules: {
    bar: {
      args: [{
        name: 'baz',
        assert: joi.string()
      }],
      validate(value, helpers, args, rule){
        return { value }
      }
    }
  }
}

// assume this is in the first library that uses Joi
const Joi = joi.extend(extension)

// assume this is another library or another direct usage. this call will produce an error
const Joi2 = joi.extend(extension)

What was the result you got?

Validation error.

What result did you expect?

For extension objects to be reusable without errors. Extend seems as if it should not have side effects on the extension objects passed.

brianle1301 commented 4 years ago

@nlundquist What exactly was the error?

nlundquist commented 4 years ago

It's a validation error due to the argsByName key being present at extension.rules.bar.argsByName. That key is added by Joi during the first call to .extend: https://github.com/sideway/joi/blob/9cffab90039c313ca62d473d01993b492dd4d007/lib/extend.js#L111

brianle1301 commented 4 years ago

@nlundquist Thanks, I can verify this.

mbargiel commented 2 years ago

We recently ran into this problem when we tried using rewire on a module where we used a single Joi.extend call. The module was probably required by other modules in addition to this rewire so the same extension was being registered twice. The second result in this "rules.compare.argsByName" is not allowed error while rewiring our module.

I second that:

What result did you expect?

For extension objects to be reusable without errors. Extend seems as if it should not have side effects on the extension objects passed.

Marsup commented 2 years ago

It's usually assumed that people are using the modern way of writing extensions, that is with a factory function, but you're right that it shouldn't modify the args anyway.