fastify / fast-json-stringify

2x faster than JSON.stringify()
MIT License
3.52k stars 208 forks source link

Error using stringify on schema with uri-encoded definition property containing anyOf, allOf or oneOf #740

Open JonathanMonroeU opened 2 months ago

JonathanMonroeU commented 2 months ago

Prerequisites

Fastify version

Latest version

Plugin version

6.0.0

Node.js version

20.1.0

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

22.04.4 LTS

Description

While using stringify I started getting "can't resolve reference" error. It seems that when you have a definition property using a uri-encoding like '%3C' or '%22', and this property has fields contaning oneOf, allOf or anyOf, it returns the error.

The following code can be run on the fast-json-stringify test suite to confirm the error.

'use strict'

const { test } = require('tap')
const build = require('..')

process.env.TZ = 'UTC'

test('ref internal - properties', (t) => {
  t.plan(1)

  const schema = {
    title: 'object with $ref',
    definitions: {
      'Some%3Cloremipsum%3E': {
          additionalProperties: {
            oneOf: [
              { type: 'string' },
              { type: 'number' },
              { type: 'object' },
              { type: 'null' }
            ]
          },
          type: 'object'
      }
    },
    type: 'object',
    properties: {
      obj: {
        $ref: '#/definitions/Some%3Cloremipsum%3E'
      }
    }
  }

  const object = {
    obj: {
      str: 'test'
    }
  }

  const stringify = build(schema)
  const output = stringify(object)

  JSON.parse(output)
  t.pass()

  t.equal(output, '{"obj":{"str":"test"}}')
})

The error exhibited is

FAIL  test/anyof.test.js 1 failed of 1 1.183s
 ✖ ref internal - properties > can't resolve reference
   #/definitions/Some%3Cloremipsum%3E from id __fjs_root_0
    node_modules/ajv/lib/vocabularies/core/ref.ts                            
     16     const {root} = env                                               
     17     if (($ref === "#" || $ref === "#/") && baseId === root.baseId) 
    return callRootRef()
     18     const schOrEnv = resolveRef.call(self, root, baseId, $ref)       
     19     if (schOrEnv === undefined) throw new 
    MissingRefError(it.opts.uriResolver, baseId, $ref)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛                              
     20     if (schOrEnv instanceof SchemaEnv) return callValidate(schOrEnv) 
     21     return inlineRefSchema(schOrEnv)                                 
     22                                                                      
     23     function callRootRef(): void {                                   
    missingRef: __fjs_root_0#/definitions/Some%3Cloremipsum%3E
    missingSchema: __fjs_root_0
    tapCaught: testFunctionThrow
    Object.code (node_modules/ajv/lib/vocabularies/core/ref.ts:19:39)
    keywordCode (node_modules/ajv/lib/compile/validate/index.ts:532:9)
    <anonymous> (node_modules/ajv/lib/compile/validate/index.ts:228:21)
    CodeGen.code (node_modules/ajv/lib/compile/codegen/index.ts:545:33)
    CodeGen.block (node_modules/ajv/lib/compile/codegen/index.ts:700:20)
    schemaKeywords (node_modules/ajv/lib/compile/validate/index.ts:228:9)
    typeAndKeywords (node_modules/ajv/lib/compile/validate/index.ts:161:3)
    subSchemaObjCode (node_modules/ajv/lib/compile/validate/index.ts:147:3)
    subschemaCode (node_modules/ajv/lib/compile/validate/index.ts:124:7)
    KeywordCxt.subschema 
        (node_modules/ajv/lib/compile/validate/index.ts:500:5)

Removing the '%' on the definition property OR removing oneOf like in the following code returns no error.

'Some%3Cloremipsum%3E': {
    additionalProperties: {
         type: 'string' ,
    },
    type: 'object'
}

Link to code that reproduces the bug

No response

Expected Behavior

No response

mcollina commented 1 month ago

Thanks for reporting! Would you like to send a Pull Request to address this issue? Remember to add unit tests.