stoplightio / spectral

A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v3.1, v3.0, and v2.0 as well as AsyncAPI v2.x.
https://stoplight.io/spectral
Apache License 2.0
2.43k stars 235 forks source link

comparing given value with other value within jsonpath #2534

Closed doh10002 closed 11 months ago

doh10002 commented 11 months ago

Describe the bug it is hard to say its a bug, but i am trying to create a custom function that can compare the given value with another value is jsonpath. for example '$.info.version' of 'v2' has to match the first part of the paths. instead me putting version number in rule, i want the rule to dynamically select the version to compare it with all the paths i selected all the paths using give, but how can i grab '$.info.version' value in custom function?

{ "info": { "version": "v2", } }, "paths": { "/v2/testRequest": {} } }

customFunction.ts

export default createRulesetFunction(
  {
    input: null,
    options: {
      type: "object",
      additionalProperties: true,
      properties: {
        value: true,
          versionPath: true
      },
      required: ["value", "versionPath"],
    },
  },
  function versionControl(targetVal: any , options: any) :IFunctionResult[] {
      const { value } = options;
      const { versionPath } = options;
      // const test = new RegExp("/v[1-9][0-9]*/")

    const versionPattern = /(v[1-9][0-9]*)/g
    const exist = versionPattern.exec(targetVal)
    // const many = exist.length

     if (targetVal !== value) {
      return [
        {
          message: `Must include ${versionPath}.`,
        },
      ];
    }
    return [];
  },
);

Expected behavior need spectral to check the versions with first part of given

P0lip commented 11 months ago

You can give this a try. I haven't tested it, but it should work.

import { isPlainObject } from '@stoplight/json';
import { createRulesetFunction } from '@stoplight/spectral-core';

type Input = string;
type Options = {
  value: unknown;
  versionPath: unknown;
  [key: string]: unknown;
};

function getVersion(data: unknown): string | null {
  if (isPlainObject(data) && isPlainObject(data.info) && typeof data.info.version === 'string') {
    return data.info.version;
  }

  return null;
}

export default createRulesetFunction<Input, Options>(
  {
    input: {
      type: 'string',
    },
    options: {
      type: 'object',
      additionalProperties: true,
      properties: {
        value: true,
        versionPath: true,
      },
      required: ['value', 'versionPath'],
    },
  },
  function versionControl(targetVal, options, { document }) {
    const { value } = options;
    const { versionPath } = options;
    const version = getVersion(document);

    if (version === null) {
      return [
        {
          message: 'Document does not contain valid version',
          path: ['info', 'version']
        }
      ]
    }

    // const test = new RegExp("/v[1-9][0-9]*/")

    const versionPattern = /(v[1-9][0-9]*)/g;
    const exist = versionPattern.exec(targetVal);
    // const many = exist.length

    if (targetVal !== value) {
      return [
        {
          message: `Must include ${versionPath}.`,
        },
      ];
    }
    return [];
  },
);