From 13ac9454d075342528d7d1f9552b974395a1373c Mon Sep 17 00:00:00 2001
From: delvedor <tommydelved@gmail.com>
Date: Sat, 11 Mar 2017 18:10:59 +0100
Subject: [PATCH 1/2] Added  for arrays and keep the reference of the full
 schema for refFinder

---
 index.js | 50 +++++++++++++++++++++++++++-----------------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/index.js b/index.js
index b25af465..65d627a6 100644
--- a/index.js
+++ b/index.js
@@ -25,7 +25,7 @@ function build (schema, options) {
   switch (schema.type) {
     case 'object':
       main = '$main'
-      code = buildObject(schema, code, main, options.schema)
+      code = buildObject(schema, code, main, options.schema, schema)
       break
     case 'string':
       main = $asString.name
@@ -42,7 +42,7 @@ function build (schema, options) {
       break
     case 'array':
       main = '$main'
-      code = buildArray(schema, code, main, options.schema)
+      code = buildArray(schema, code, main, options.schema, schema)
       break
     default:
       throw new Error(`${schema.type} unsupported`)
@@ -72,7 +72,7 @@ function $asNumber (i) {
 }
 
 function $asBoolean (bool) {
-  return bool && 'true' || 'false'
+  return bool && 'true' || 'false' // eslint-disable-line
 }
 
 function $asString (str) {
@@ -116,7 +116,7 @@ function $asStringSmall (str) {
   return point < 32 ? JSON.stringify(str) : '"' + result + '"'
 }
 
-function addPatternProperties (schema, externalSchema) {
+function addPatternProperties (schema, externalSchema, fullSchema) {
   var pp = schema.patternProperties
   let code = `
       var keys = Object.keys(obj)
@@ -125,19 +125,19 @@ function addPatternProperties (schema, externalSchema) {
   `
   Object.keys(pp).forEach((regex, index) => {
     if (pp[regex]['$ref']) {
-      pp[regex] = refFinder(pp[regex]['$ref'], schema, externalSchema)
+      pp[regex] = refFinder(pp[regex]['$ref'], fullSchema, externalSchema, fullSchema)
     }
     var type = pp[regex].type
     code += `
         if (/${regex}/.test(keys[i])) {
     `
     if (type === 'object') {
-      code += buildObject(pp[regex], '', 'buildObjectPP' + index, externalSchema)
+      code += buildObject(pp[regex], '', 'buildObjectPP' + index, externalSchema, fullSchema)
       code += `
           json += $asString(keys[i]) + ':' + buildObjectPP${index}(obj[keys[i]]) + ','
       `
     } else if (type === 'array') {
-      code += buildArray(pp[regex], '', 'buildArrayPP' + index, externalSchema)
+      code += buildArray(pp[regex], '', 'buildArrayPP' + index, externalSchema, fullSchema)
       code += `
           json += $asString(keys[i]) + ':' + buildArrayPP${index}(obj[keys[i]]) + ','
       `
@@ -169,7 +169,7 @@ function addPatternProperties (schema, externalSchema) {
     `
   })
   if (schema.additionalProperties) {
-    code += additionalProperty(schema, externalSchema)
+    code += additionalProperty(schema, externalSchema, fullSchema)
   }
 
   code += `
@@ -178,7 +178,7 @@ function addPatternProperties (schema, externalSchema) {
   return code
 }
 
-function additionalProperty (schema, externalSchema) {
+function additionalProperty (schema, externalSchema, fullSchema) {
   var ap = schema.additionalProperties
   let code = ''
   if (ap === true) {
@@ -187,7 +187,7 @@ function additionalProperty (schema, externalSchema) {
     `
   }
   if (ap['$ref']) {
-    ap = refFinder(ap['$ref'], schema, externalSchema)
+    ap = refFinder(ap['$ref'], fullSchema, externalSchema)
   }
 
   let type = ap.type
@@ -197,7 +197,7 @@ function additionalProperty (schema, externalSchema) {
         json += $asString(keys[i]) + ':' + buildObjectAP(obj[keys[i]]) + ','
     `
   } else if (type === 'array') {
-    code += buildArray(ap, '', 'buildArrayAP', externalSchema)
+    code += buildArray(ap, '', 'buildArrayAP', externalSchema, fullSchema)
     code += `
         json += $asString(keys[i]) + ':' + buildArrayAP(obj[keys[i]]) + ','
     `
@@ -225,12 +225,12 @@ function additionalProperty (schema, externalSchema) {
   return code
 }
 
-function addAdditionalProperties (schema, externalSchema) {
+function addAdditionalProperties (schema, externalSchema, fullSchema) {
   return `
       var keys = Object.keys(obj)
       for (var i = 0; i < keys.length; i++) {
         if (properties[keys[i]]) continue
-        ${additionalProperty(schema, externalSchema)}
+        ${additionalProperty(schema, externalSchema, fullSchema)}
       }
   `
 }
@@ -250,16 +250,16 @@ function refFinder (ref, schema, externalSchema) {
   return (new Function('schema', code))(schema)
 }
 
-function buildObject (schema, code, name, externalSchema) {
+function buildObject (schema, code, name, externalSchema, fullSchema) {
   code += `
     function ${name} (obj) {
       var json = '{'
   `
 
   if (schema.patternProperties) {
-    code += addPatternProperties(schema, externalSchema)
+    code += addPatternProperties(schema, externalSchema, fullSchema)
   } else if (schema.additionalProperties && !schema.patternProperties) {
-    code += addAdditionalProperties(schema, externalSchema)
+    code += addAdditionalProperties(schema, externalSchema, fullSchema)
   }
 
   var laterCode = ''
@@ -273,10 +273,10 @@ function buildObject (schema, code, name, externalSchema) {
       `
 
     if (schema.properties[key]['$ref']) {
-      schema.properties[key] = refFinder(schema.properties[key]['$ref'], schema, externalSchema)
+      schema.properties[key] = refFinder(schema.properties[key]['$ref'], fullSchema, externalSchema)
     }
 
-    const result = nested(laterCode, name, '.' + key, schema.properties[key], externalSchema)
+    const result = nested(laterCode, name, '.' + key, schema.properties[key], externalSchema, fullSchema)
 
     code += result.code
     laterCode = result.laterCode
@@ -312,7 +312,7 @@ function buildObject (schema, code, name, externalSchema) {
   return code
 }
 
-function buildArray (schema, code, name, externalSchema) {
+function buildArray (schema, code, name, externalSchema, fullSchema) {
   code += `
     function ${name} (obj) {
       var json = '['
@@ -320,7 +320,11 @@ function buildArray (schema, code, name, externalSchema) {
 
   var laterCode = ''
 
-  const result = nested(laterCode, name, '[i]', schema.items, externalSchema)
+  if (schema.items['$ref']) {
+    schema.items = refFinder(schema.items['$ref'], fullSchema, externalSchema)
+  }
+
+  const result = nested(laterCode, name, '[i]', schema.items, externalSchema, fullSchema)
 
   code += `
     const l = obj.length
@@ -346,7 +350,7 @@ function buildArray (schema, code, name, externalSchema) {
   return code
 }
 
-function nested (laterCode, name, key, schema, externalSchema) {
+function nested (laterCode, name, key, schema, externalSchema, fullSchema) {
   var code = ''
   var funcName
   const type = schema.type
@@ -374,14 +378,14 @@ function nested (laterCode, name, key, schema, externalSchema) {
       break
     case 'object':
       funcName = (name + key).replace(/[-.\[\]]/g, '') // eslint-disable-line
-      laterCode = buildObject(schema, laterCode, funcName, externalSchema)
+      laterCode = buildObject(schema, laterCode, funcName, externalSchema, fullSchema)
       code += `
         json += ${funcName}(obj${key})
       `
       break
     case 'array':
       funcName = (name + key).replace(/[-.\[\]]/g, '') // eslint-disable-line
-      laterCode = buildArray(schema, laterCode, funcName, externalSchema)
+      laterCode = buildArray(schema, laterCode, funcName, externalSchema, fullSchema)
       code += `
         json += ${funcName}(obj${key})
       `

From beb1ddc2300612247b6260ad43083d08c047ce3a Mon Sep 17 00:00:00 2001
From: delvedor <tommydelved@gmail.com>
Date: Sat, 11 Mar 2017 18:11:09 +0100
Subject: [PATCH 2/2] Updated test

---
 test/ref.test.js | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/test/ref.test.js b/test/ref.test.js
index c6b0c2fe..7bbff0a9 100644
--- a/test/ref.test.js
+++ b/test/ref.test.js
@@ -45,6 +45,42 @@ test('ref internal - properties', (t) => {
   t.equal('{"obj":{"str":"test"}}', output)
 })
 
+test('ref internal - items', (t) => {
+  t.plan(2)
+
+  const schema = {
+    title: 'array with $ref',
+    definitions: {
+      def: {
+        type: 'object',
+        properties: {
+          str: {
+            type: 'string'
+          }
+        }
+      }
+    },
+    type: 'array',
+    items: { $ref: '#/definitions/def' }
+  }
+
+  const array = [{
+    str: 'test'
+  }]
+
+  const stringify = build(schema)
+  const output = stringify(array)
+
+  try {
+    JSON.parse(output)
+    t.pass()
+  } catch (e) {
+    t.fail()
+  }
+
+  t.equal('[{"str":"test"}]', output)
+})
+
 test('ref external - properties', (t) => {
   t.plan(2)
 
@@ -286,3 +322,59 @@ test('ref external - pattern-additional Properties', (t) => {
 
   t.equal('{"reg":{"str":"test"},"obj":{"int":42}}', output)
 })
+
+test('ref internal - deepObject schema', (t) => {
+  t.plan(2)
+
+  const schema = {
+    title: 'object with $ref',
+    definitions: {
+      def: {
+        type: 'object',
+        properties: {
+          coming: {
+            type: 'object',
+            properties: {
+              where: {
+                type: 'string'
+              }
+            }
+          }
+        }
+      }
+    },
+    type: 'object',
+    properties: {
+      winter: {
+        type: 'object',
+        properties: {
+          is: {
+            $ref: '#/definitions/def'
+          }
+        }
+      }
+    }
+  }
+
+  const object = {
+    winter: {
+      is: {
+        coming: {
+          where: 'to town'
+        }
+      }
+    }
+  }
+
+  const stringify = build(schema)
+  const output = stringify(object)
+
+  try {
+    JSON.parse(output)
+    t.pass()
+  } catch (e) {
+    t.fail()
+  }
+
+  t.equal('{"winter":{"is":{"coming":{"where":"to town"}}}}', output)
+})