Repository: gabriel-vasile/mimetype
Pull request #219 (2021-12-13 14:55:13)

Require NdJSON to contain arrays and objects
Previously, a files containing only JSON basic data types would be
reported as NdJSON. This change makeѕ NdJSON require to contain at least
one array or one object.

This is required so files containing
```json
1
2
3
```
are not reported as ndjson. This is more inline with JSON detection, which also does not pass for single basic data types.


Patch:
diff --git a/internal/magic/text.go b/internal/magic/text.go
index 40bfb19..dff756c 100644
--- a/internal/magic/text.go
+++ b/internal/magic/text.go
@@ -228,9 +228,11 @@ func GeoJSON(raw []byte, limit uint32) bool {
 	return false
 }
 
-// NdJSON matches a Newline delimited JSON file.
+// NdJSON matches a Newline delimited JSON file. All complete lines from raw
+// must be valid JSON documents meaning they contain one of the valid JSON data
+// types.
 func NdJSON(raw []byte, limit uint32) bool {
-	lCount := 0
+	lCount, hasObjOrArr := 0, false
 	sc := bufio.NewScanner(dropLastLine(raw, limit))
 	for sc.Scan() {
 		l := sc.Bytes()
@@ -242,10 +244,13 @@ func NdJSON(raw []byte, limit uint32) bool {
 		if err != nil {
 			return false
 		}
+		if l[0] == '[' || l[0] == '{' {
+			hasObjOrArr = true
+		}
 		lCount++
 	}
 
-	return lCount > 1
+	return lCount > 1 && hasObjOrArr
 }
 
 // Har matches a HAR Spec file.


Test patch:
diff --git a/internal/json/json_test.go b/internal/json/json_test.go
index 38422ba..39ae2cb 100644
--- a/internal/json/json_test.go
+++ b/internal/json/json_test.go
@@ -19,6 +19,12 @@ func TestScan(t *testing.T) {
 		{`}{`, 1, false},
 		{`{]`, 2, false},
 		{`{}`, 2, true},
+		{`[]`, 2, true},
+		{`"foo"`, 5, true},
+		{`120`, 3, true},
+		{`1e20`, 4, true},
+		{`0.120`, 5, true},
+		{`null`, 4, true},
 		{`{"foo":"bar"}`, 13, true},
 		{`{"foo":"21\t\u0009 \u1234","bar":{"baz":["qux"]}`, 48, false},
 		{`{"foo":"bar","bar":{"baz":["qux"]}}`, 35, true},
diff --git a/internal/magic/magic_test.go b/internal/magic/magic_test.go
index 6dd5c0b..d0a5d8a 100644
--- a/internal/magic/magic_test.go
+++ b/internal/magic/magic_test.go
@@ -27,6 +27,55 @@ func TestMagic(t *testing.T) {
 			limit:    10,
 			res:      true,
 		},
+		{
+			name:     "basic JSON data type null",
+			detector: JSON,
+			raw:      `null`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "basic JSON data type string",
+			detector: JSON,
+			raw:      `"abc"`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "basic JSON data type integer",
+			detector: JSON,
+			raw:      `120`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "basic JSON data type float",
+			detector: JSON,
+			raw:      `.120`,
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "NdJSON with basic data types",
+			detector: NdJSON,
+			raw:      "1\nnull\n\"foo\"\n0.1",
+			limit:    10,
+			res:      false,
+		},
+		{
+			name:     "NdJSON with basic data types and empty object",
+			detector: NdJSON,
+			raw:      "1\n2\n3\n{}",
+			limit:    10,
+			res:      true,
+		},
+		{
+			name:     "NdJSON with empty objects types",
+			detector: NdJSON,
+			raw:      "{}\n{}\n{}",
+			limit:    10,
+			res:      true,
+		},
 	}
 	for _, tt := range tCases {
 		t.Run(tt.name, func(t *testing.T) {