From 6fd581d173a9f28167457b24b356c02f00be7ba9 Mon Sep 17 00:00:00 2001
From: shreyas-goenka <88374338+shreyas-goenka@users.noreply.github.com>
Date: Thu, 25 Apr 2024 16:50:45 +0530
Subject: [PATCH] Allow variable references in non-string fields in the JSON
schema (#1398)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Tests
Verified manually.
Before:
After:
Manually verified the schema diff is sane. Example:
```
< "type": "boolean",
< "description": "If inference tables are enabled or not. NOTE: If you have already disabled payload logging once, you cannot enable again."
---
> "description": "If inference tables are enabled or not. NOTE: If you have already disabled payload logging once, you cannot enable again.",
> "anyOf": [
> {
> "type": "boolean"
> },
> {
> "type": "string",
> "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
> }
> ]
```
---
bundle/schema/schema.go | 17 ++
bundle/schema/schema_test.go | 490 +++++++++++++++++++++++++++++++----
libs/dyn/dynvar/ref.go | 4 +-
3 files changed, 457 insertions(+), 54 deletions(-)
diff --git a/bundle/schema/schema.go b/bundle/schema/schema.go
index b37f72d9..ac0b4f2e 100644
--- a/bundle/schema/schema.go
+++ b/bundle/schema/schema.go
@@ -6,6 +6,7 @@ import (
"reflect"
"strings"
+ "github.com/databricks/cli/libs/dyn/dynvar"
"github.com/databricks/cli/libs/jsonschema"
)
@@ -167,6 +168,22 @@ func toSchema(golangType reflect.Type, docs *Docs, tracker *tracker) (*jsonschem
}
jsonSchema := &jsonschema.Schema{Type: rootJavascriptType}
+ // If the type is a non-string primitive, then we allow it to be a string
+ // provided it's a pure variable reference (ie only a single variable reference).
+ if rootJavascriptType == jsonschema.BooleanType || rootJavascriptType == jsonschema.NumberType {
+ jsonSchema = &jsonschema.Schema{
+ AnyOf: []*jsonschema.Schema{
+ {
+ Type: rootJavascriptType,
+ },
+ {
+ Type: jsonschema.StringType,
+ Pattern: dynvar.VariableRegex,
+ },
+ },
+ }
+ }
+
if docs != nil {
jsonSchema.Description = docs.Description
}
diff --git a/bundle/schema/schema_test.go b/bundle/schema/schema_test.go
index d44a2082..ea4fd102 100644
--- a/bundle/schema/schema_test.go
+++ b/bundle/schema/schema_test.go
@@ -14,7 +14,15 @@ func TestIntSchema(t *testing.T) {
expected :=
`{
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}`
schema, err := New(reflect.TypeOf(elemInt), nil)
@@ -33,7 +41,15 @@ func TestBooleanSchema(t *testing.T) {
expected :=
`{
- "type": "boolean"
+ "anyOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}`
schema, err := New(reflect.TypeOf(elem), nil)
@@ -101,46 +117,150 @@ func TestStructOfPrimitivesSchema(t *testing.T) {
"type": "object",
"properties": {
"bool_val": {
- "type": "boolean"
+ "anyOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"float32_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"float64_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"int16_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"int32_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"int64_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"int8_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"int_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"string_val": {
"type": "string"
},
"uint16_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"uint32_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"uint64_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"uint8_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"uint_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -200,7 +320,15 @@ func TestStructOfStructsSchema(t *testing.T) {
"type": "object",
"properties": {
"a": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"b": {
"type": "string"
@@ -257,7 +385,15 @@ func TestStructOfMapsSchema(t *testing.T) {
"my_map": {
"type": "object",
"additionalProperties": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
}
},
@@ -339,7 +475,15 @@ func TestMapOfPrimitivesSchema(t *testing.T) {
`{
"type": "object",
"additionalProperties": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
}`
@@ -368,7 +512,15 @@ func TestMapOfStructSchema(t *testing.T) {
"type": "object",
"properties": {
"my_int": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -398,7 +550,15 @@ func TestMapOfMapSchema(t *testing.T) {
"additionalProperties": {
"type": "object",
"additionalProperties": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
}
}`
@@ -495,7 +655,15 @@ func TestSliceOfMapSchema(t *testing.T) {
"items": {
"type": "object",
"additionalProperties": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
}
}`
@@ -525,7 +693,15 @@ func TestSliceOfStructSchema(t *testing.T) {
"type": "object",
"properties": {
"my_int": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -575,7 +751,15 @@ func TestEmbeddedStructSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"country": {
"type": "string"
@@ -607,7 +791,15 @@ func TestEmbeddedStructSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"home": {
"type": "object",
@@ -694,7 +886,15 @@ func TestNonAnnotatedFieldsAreSkipped(t *testing.T) {
"type": "object",
"properties": {
"bar": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -728,7 +928,15 @@ func TestDashFieldsAreSkipped(t *testing.T) {
"type": "object",
"properties": {
"bar": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -773,7 +981,15 @@ func TestPointerInStructSchema(t *testing.T) {
"type": "object",
"properties": {
"ptr_val2": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -782,13 +998,29 @@ func TestPointerInStructSchema(t *testing.T) {
]
},
"float_val": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"ptr_bar": {
"type": "object",
"properties": {
"ptr_val2": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -797,7 +1029,15 @@ func TestPointerInStructSchema(t *testing.T) {
]
},
"ptr_int": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"ptr_string": {
"type": "string"
@@ -860,7 +1100,15 @@ func TestGenericSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"name": {
"type": "string"
@@ -875,7 +1123,15 @@ func TestGenericSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"name": {
"type": "string"
@@ -895,7 +1151,15 @@ func TestGenericSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"name": {
"type": "string"
@@ -910,7 +1174,15 @@ func TestGenericSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"name": {
"type": "string"
@@ -932,7 +1204,15 @@ func TestGenericSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"name": {
"type": "string"
@@ -950,7 +1230,15 @@ func TestGenericSchema(t *testing.T) {
"type": "object",
"properties": {
"age": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"name": {
"type": "string"
@@ -1028,16 +1316,40 @@ func TestFieldsWithoutOmitEmptyAreRequired(t *testing.T) {
"type": "object",
"properties": {
"apple": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"bar": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"papaya": {
"type": "object",
"properties": {
"a": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"b": {
"type": "string"
@@ -1111,7 +1423,15 @@ func TestDocIngestionForObject(t *testing.T) {
"description": "docs for a"
},
"b": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -1185,12 +1505,28 @@ func TestDocIngestionForSlice(t *testing.T) {
"type": "object",
"properties": {
"guava": {
- "type": "number",
- "description": "docs for guava"
+ "description": "docs for guava",
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"pineapple": {
- "type": "number",
- "description": "docs for pineapple"
+ "description": "docs for pineapple",
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -1268,12 +1604,28 @@ func TestDocIngestionForMap(t *testing.T) {
"type": "object",
"properties": {
"apple": {
- "type": "number",
- "description": "docs for apple"
+ "description": "docs for apple",
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"mango": {
- "type": "number",
- "description": "docs for mango"
+ "description": "docs for mango",
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -1324,8 +1676,16 @@ func TestDocIngestionForTopLevelPrimitive(t *testing.T) {
"description": "docs for root",
"properties": {
"my_val": {
- "type": "number",
- "description": "docs for my val"
+ "description": "docs for my val",
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
}
},
"additionalProperties": false,
@@ -1395,7 +1755,15 @@ func TestInterfaceGeneratesEmptySchema(t *testing.T) {
"type": "object",
"properties": {
"apple": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"mango": {}
},
@@ -1436,7 +1804,15 @@ func TestBundleReadOnlytag(t *testing.T) {
"type": "object",
"properties": {
"apple": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"pokemon": {
"type": "object",
@@ -1488,7 +1864,15 @@ func TestBundleInternalTag(t *testing.T) {
"type": "object",
"properties": {
"apple": {
- "type": "number"
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\\}"
+ }
+ ]
},
"pokemon": {
"type": "object",
diff --git a/libs/dyn/dynvar/ref.go b/libs/dyn/dynvar/ref.go
index a2047032..e6340269 100644
--- a/libs/dyn/dynvar/ref.go
+++ b/libs/dyn/dynvar/ref.go
@@ -6,7 +6,9 @@ import (
"github.com/databricks/cli/libs/dyn"
)
-var re = regexp.MustCompile(`\$\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\}`)
+const VariableRegex = `\$\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\}`
+
+var re = regexp.MustCompile(VariableRegex)
// ref represents a variable reference.
// It is a string [dyn.Value] contained in a larger [dyn.Value].