Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

Supporting optional jsonValueValidator in Operator class?

Aberta
#412 3 comentários 1 reação 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
3/5
Tempo estimado
1-2 dias
Facilidade para iniciantes
42/100
Tipo de issue
Funcionalidade
Clareza
Razoavelmente clara
Status de atividade
Estagnada
Stack de tecnologia
javascript
Domínio
backend

Direção de pesquisa

Comece com src/operator.js e a configuração padrão de operadores em src/engine-default-operators.js e, em seguida, reproduza os exemplos de in/notIn e contains/notContains da issue. Verifique como o jsonValueValidator opcional proposto afetaria a avaliação dos operadores; considera-se concluído quando valores que não são arrays para in/notIn são tratados de forma adequada e consistente com o comportamento documentado.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

In the documentation on JSON rules engine operators it states that the fact passed to the contains/notContains operators must be arrays. And I see in the Operator class that a factValueValidator function can be supplied to the constructor to ensure that the fact supplied to this operator meets that expectation.

Similarly, the documentation states that for in/notIn operators, the value side of the comparison must be an array. But unlike contains/notContains, there's no validation in place to check that this is the case. And that means you don't have the same graceful handling when a non-array value is passed where an array is expected. A minimal-ish example to illustrate how in/notIn are not symmetrical to contains/notContains:

const { Engine } = require('json-rules-engine');

const facts = {
	people: {
		someguy: 'dave',
		otherguys: ['hal', 'stanley', 'alex']
	},
};

// This rule will throw an error because the path $.nonexistentPath evaluates to undefined and b.indexOf(a) throws an error
const operatorInWithNonexistentValuePathRule = {
  conditions: {
    all: [
      {
        fact: 'people',
        path: '$.someguy',
		operator: 'in', // notIn produces the same error
        value: {
          fact: 'people',
		  path: '$.nonexistentpath'
        }
      }
    ]
  },
  event: {
    type: 'in-with-nonexistent-value-path-rule',
  }
};
  
// This rule will NOT throw an error because contains operator is defined with a factValueValidator that will return false if the factValue is not an array
const operatorContainsWithNonexistentFactPathRule = {
	conditions: {
	  all: [
		{
		  fact: 'people',
		  path: '$.nonexistentpath',
		  operator: 'contains',
		  value: {
			fact: 'people',
			path: '$.someguy'
		  }
		}
	  ]
	},
	event: {
	  type: 'contains-with-nonexistent-fact-path-rule',
	}
  };

function runEngine(
	rule,
	facts
){

	const engine = new Engine();
	engine.addRule(rule);

	engine
	.run(facts)
	.then(({ failureEvents }) => {
		failureEvents.map(event => console.log(event));
	})
	.catch(console.error);
}

runEngine(operatorInWithNonexistentValuePathRule, facts);
runEngine(operatorContainsWithNonexistentFactPathRule, facts);

I'm curious if this is the intentional/desired behavior here? Naively I would've expected that in/notIn operators can (and would) validate values similarly to how contains/notContains validate facts. I think this could be accomplished with a minor rewrite to the Operator class, something like:

'use strict'

export default class Operator {
  /**
   * Constructor
   * @param {string}   name - operator identifier
   * @param {function(factValue, jsonValue)} callback - operator evaluation method
   * @param {function}  [factValueValidator] - optional validator for asserting the data type of the fact
   * @param {function}  [jsonValueValidator] - optional validator for asserting the data type of the "value" property of the condition
   * @returns {Operator} - instance
   */
  constructor (name, cb, factValueValidator) {
    this.name = String(name)
    if (!name) throw new Error('Missing operator name')
    if (typeof cb !== 'function') throw new Error('Missing operator callback')
    this.cb = cb
    this.factValueValidator = factValueValidator
    if (!this.factValueValidator) this.factValueValidator = () => true
    this.jsonValueValidator = jsonValueValidator
    if (!this.jsonValueValidator) this.jsonValueValidator = () => true
  }

  /**
   * Takes the fact result and compares it to the condition 'value', using the callback
   * @param   {mixed} factValue - fact result
   * @param   {mixed} jsonValue - "value" property of the condition
   * @returns {Boolean} - whether the values pass the operator test
   */
  evaluate (factValue, jsonValue) {
    return this.factValueValidator(factValue) && this.jsonValueValidator(jsonValue) && this.cb(factValue, jsonValue)
  }
}

And tweaking the initialization of the default engine operators. If there's interest in doing something along these lines I'd be glad to try and throw together a small PR.

Linguagem predominante
JavaScript
Estrelas
3.1k
Forks
507
Métricas de merge de PRs
Nenhum PR com merge em 30d

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de CacheControl/json-rules-engine

Todas as issues de CacheControl/json-rules-engine

Issues semelhantes

Mais issues de JavaScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.