Skip to content

Commit

Permalink
fix: duplicate types generated #26 (#27)
Browse files Browse the repository at this point in the history
* add test code

* fix code

* code format

* fix code

* code format

* add test code

* bump patch
  • Loading branch information
jiro4989 authored Apr 8, 2022
1 parent 49acbdb commit b20b443
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 7 deletions.
2 changes: 1 addition & 1 deletion nimjson.nimble
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Package

version = "2.0.0"
version = "2.0.1"
author = "jiro4989"
description = "nimjson generates nim object definitions from json documents."
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/nimjson.nim
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ when not defined(js):

const
appName = "nimjson"
version = &"""{appName} command version 2.0.0
version = &"""{appName} command version 2.0.1
Copyright (c) 2019 jiro4989
Released under the MIT License.
https://github.com/jiro4989/nimjson"""
Expand Down
40 changes: 35 additions & 5 deletions src/nimjsonpkg/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,54 @@ func kind2str(kind: JsonNodeKind): string =
of JNull: "NilType"
else: ""

func originalOrNumberedTypeName(typeNamebuffer: var Table[string, bool],
typeName: string): string =
## This procedure adds a number to suffix if type names are duplicated.
if not typeNamebuffer.hasKey(typeName):
typeNamebuffer[typeName] = true
return typeName
var i = 2
result = typeName & $i
while typeNamebuffer.hasKey(result):
inc i
result = typeName & $i
typeNamebuffer[result] = true

proc parse(jsonNode: JsonNode, defs: var seq[ObjectDefinition],
defIndex: int, objectName: string, isPublic, forceBackquote, isSeq: bool) =
defIndex: int, objectName: string, isPublic, forceBackquote, isSeq: bool,
typeNameBuffer: var Table[string, bool]) =
## Parse Json Node.
## This procedure adds a number to suffix if type names are duplicated.
case jsonNode.kind
of JObject:
let defIndex = defs.len
defs.add(newObjectDefinition(objectName.headUpper, false, isPublic,
forceBackquote))
for name, node in jsonNode.fields:
var name = name
case node.kind
of JObject:
let srcName = name
name = originalOrNumberedTypeName(typeNameBuffer, name)
let typ = name.headUpper
let fieldDef = newFieldDefinition(name, typ, isPublic, forceBackquote, false)
let fieldDef = newFieldDefinition(srcName, typ, isPublic,
forceBackquote, false)
defs[defIndex].addFieldDefinition(fieldDef)
of JArray:
if 0 < node.elems.len and node.elems[0].kind == JObject:
let srcName = name
name = originalOrNumberedTypeName(typeNameBuffer, name)
let typ = name.headUpper
let fieldDef = newFieldDefinition(name, typ, isPublic, forceBackquote, true)
let fieldDef = newFieldDefinition(srcName, typ, isPublic,
forceBackquote, true)
defs[defIndex].addFieldDefinition(fieldDef)
else: discard

node.parse(defs, defIndex, name, isPublic, forceBackquote, false)
node.parse(defs, defIndex, name, isPublic, forceBackquote, false, typeNameBuffer)
of JArray:
if 0 < jsonNode.elems.len:
let child = jsonNode.elems[0]
child.parse(defs, defIndex, objectName, isPublic, forceBackquote, true)
child.parse(defs, defIndex, objectName, isPublic, forceBackquote, true, typeNameBuffer)
else:
let typ = "NilType"
let fieldDef = newFieldDefinition(objectName, typ, isPublic,
Expand All @@ -53,6 +76,13 @@ proc parse(jsonNode: JsonNode, defs: var seq[ObjectDefinition],
let fieldDef = newFieldDefinition(objectName, typ, isPublic, forceBackquote, isSeq)
defs[defIndex].addFieldDefinition(fieldDef)

proc parse(jsonNode: JsonNode, defs: var seq[ObjectDefinition],
defIndex: int, objectName: string, isPublic, forceBackquote, isSeq: bool) =
## Parse Json Node.
## This procedure adds a number to suffix if type names are duplicated.
var typeNameBuffer = initTable[string, bool]()
jsonNode.parse(defs, defIndex, objectName, isPublic, forceBackquote, isSeq, typeNameBuffer)

proc parseAndGetString*(jsonNode: JsonNode, objectName: string, isPublic,
forceBackquote: bool): string =
var defs: seq[ObjectDefinition]
Expand Down
157 changes: 157 additions & 0 deletions tests/test_parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,36 @@ import std/json

include nimjsonpkg/parser

block:
checkpoint "normal: [originalOrNumberedTypeName] no duplicated type name"
var buf = initTable[string, bool]()
let name = "Sushi"
let got = originalOrNumberedTypeName(buf, name)
check got == "Sushi"
check buf.hasKey("Sushi")

block:
checkpoint "normal: [originalOrNumberedTypeName] duplicated type name exists"
var buf = initTable[string, bool]()
buf["Sushi"] = true
let name = "Sushi"
let got = originalOrNumberedTypeName(buf, name)
check got == "Sushi2"
check buf.hasKey("Sushi")
check buf.hasKey("Sushi2")

block:
checkpoint "normal: [originalOrNumberedTypeName] duplicated type name exists 2"
var buf = initTable[string, bool]()
buf["Sushi"] = true
buf["Sushi2"] = true
let name = "Sushi"
let got = originalOrNumberedTypeName(buf, name)
check got == "Sushi3"
check buf.hasKey("Sushi")
check buf.hasKey("Sushi2")
check buf.hasKey("Sushi3")

block:
checkpoint "正常系: プリミティブなフィールドのみ"
let j = """{"a":1, "b":true, "c":3.14, "d":null, "e":"hello"}""".parseJson
Expand Down Expand Up @@ -234,3 +264,130 @@ block:
want4.addFieldDefinition(newFieldDefinition("age", "int64", false, false, false))

check defs == @[want1, want2, want3, want4]

block:
checkpoint "正常系: 同じフィールド名のサブタイプが複数存在したとき、名前が衝突しない"
let j = """
{
"obj1": {
"subtype": {"a": 1}
},
"obj2": {
"subtype": {"b": 1}
}
}
""".parseJson
var defs: seq[ObjectDefinition]
j.parse(defs, 0, "Object", false, false, false)

var want1 = newObjectDefinition("Object", false, false, false)
want1.addFieldDefinition(newFieldDefinition("obj1", "Obj1", false, false, false))
want1.addFieldDefinition(newFieldDefinition("obj2", "Obj2", false, false, false))

var want2 = newObjectDefinition("Obj1", false, false, false)
want2.addFieldDefinition(newFieldDefinition("subtype", "Subtype", false,
false, false))

var want3 = newObjectDefinition("Subtype", false, false, false)
want3.addFieldDefinition(newFieldDefinition("a", "int64", false, false, false))

var want4 = newObjectDefinition("Obj2", false, false, false)
want4.addFieldDefinition(newFieldDefinition("subtype", "Subtype2", false,
false, false))

var want5 = newObjectDefinition("Subtype2", false, false, false)
want5.addFieldDefinition(newFieldDefinition("b", "int64", false, false, false))

check defs == @[want1, want2, want3, want4, want5]

block:
checkpoint "正常系: 配列の名前が衝突した場合ずらす"
let j = """
{
"obj1": {
"subtype": [{"a": 1}]
},
"obj2": {
"subtype": [{"b": 1}]
}
}
""".parseJson
var defs: seq[ObjectDefinition]
j.parse(defs, 0, "Object", false, false, false)

var want1 = newObjectDefinition("Object", false, false, false)
want1.addFieldDefinition(newFieldDefinition("obj1", "Obj1", false, false, false))
want1.addFieldDefinition(newFieldDefinition("obj2", "Obj2", false, false, false))

var want2 = newObjectDefinition("Obj1", false, false, false)
want2.addFieldDefinition(newFieldDefinition("subtype", "Subtype", false,
false, true))

var want3 = newObjectDefinition("Subtype", false, false, false)
want3.addFieldDefinition(newFieldDefinition("a", "int64", false, false, false))

var want4 = newObjectDefinition("Obj2", false, false, false)
want4.addFieldDefinition(newFieldDefinition("subtype", "Subtype2", false,
false, true))

var want5 = newObjectDefinition("Subtype2", false, false, false)
want5.addFieldDefinition(newFieldDefinition("b", "int64", false, false, false))

check defs == @[want1, want2, want3, want4, want5]

block:
checkpoint "正常系: 配列の名前が衝突した場合ずらす"
let j = """
{
"obj1": {
"subtype": {"a": 1}
},
"obj2": {
"subtype": [{"b": 1}]
},
"obj3": {
"subtype": {"a": 1}
},
"obj4": {
"subtype": [{"a": 1}]
},
}
""".parseJson
var defs: seq[ObjectDefinition]
j.parse(defs, 0, "Object", false, false, false)

var want1 = newObjectDefinition("Object", false, false, false)
want1.addFieldDefinition(newFieldDefinition("obj1", "Obj1", false, false, false))
want1.addFieldDefinition(newFieldDefinition("obj2", "Obj2", false, false, false))
want1.addFieldDefinition(newFieldDefinition("obj3", "Obj3", false, false, false))
want1.addFieldDefinition(newFieldDefinition("obj4", "Obj4", false, false, false))

var want2 = newObjectDefinition("Obj1", false, false, false)
want2.addFieldDefinition(newFieldDefinition("subtype", "Subtype", false,
false, false))

var want3 = newObjectDefinition("Subtype", false, false, false)
want3.addFieldDefinition(newFieldDefinition("a", "int64", false, false, false))

var want4 = newObjectDefinition("Obj2", false, false, false)
want4.addFieldDefinition(newFieldDefinition("subtype", "Subtype2", false,
false, true))

var want5 = newObjectDefinition("Subtype2", false, false, false)
want5.addFieldDefinition(newFieldDefinition("b", "int64", false, false, false))

var want6 = newObjectDefinition("Obj3", false, false, false)
want6.addFieldDefinition(newFieldDefinition("subtype", "Subtype3", false,
false, false))

var want7 = newObjectDefinition("Subtype3", false, false, false)
want7.addFieldDefinition(newFieldDefinition("a", "int64", false, false, false))

var want8 = newObjectDefinition("Obj4", false, false, false)
want8.addFieldDefinition(newFieldDefinition("subtype", "Subtype4", false,
false, true))

var want9 = newObjectDefinition("Subtype4", false, false, false)
want9.addFieldDefinition(newFieldDefinition("a", "int64", false, false, false))

check defs == @[want1, want2, want3, want4, want5, want6, want7, want8, want9]

0 comments on commit b20b443

Please sign in to comment.