Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonEditor: Handle anyOf, oneOf and internal ref #4256

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions catalog/app/components/JsonEditor/State.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ describe('components/JsonEditor/State', () => {
describe.skip('getJsonDictItemRecursively', () => {
const dict = {
'/c': 'found C',
'/c/__*': 'found additional',
'/c/__*/b': 'found B',
'/c/__*/b/__*': 'found item',
'/c/__items*': 'found additional',
'/c/__items*/b': 'found B',
'/c/__items*/b/__items*': 'found item',
}
expect(getJsonDictItemRecursively(dict, ['c'])).toBe('found C')
expect(getJsonDictItemRecursively(dict, ['c', 'foo'])).toBe('found additional')
Expand Down
42 changes: 40 additions & 2 deletions catalog/app/components/JsonEditor/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
COLUMN_IDS,
EMPTY_VALUE,
JSON_POINTER_PLACEHOLDER,
JSON_POINTER_ANY_OF,
JSON_POINTER_ONE_OF,
ValidationErrors,
} from './constants'

Expand Down Expand Up @@ -101,6 +103,36 @@
iterateSchema(rawItem, sortOrder, item.address, memo)
}

if (schema.anyOf) {
const item = getSchemaItem({

Check warning on line 107 in catalog/app/components/JsonEditor/State.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/components/JsonEditor/State.ts#L107

Added line #L107 was not covered by tests
item: schema,
key: JSON_POINTER_ANY_OF,
parentPath,
required: false,
sortIndex: sortOrder.current.counter,
})
memo[JSONPointer.stringify(item.address)] = item
sortOrder.current.counter += 1
schema.anyOf.forEach((rawItem: any) => {
iterateSchema(rawItem, sortOrder, item.address, memo)

Check warning on line 117 in catalog/app/components/JsonEditor/State.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/components/JsonEditor/State.ts#L114-L117

Added lines #L114 - L117 were not covered by tests
})
}
if (schema.oneOf) {
const item = getSchemaItem({

Check warning on line 121 in catalog/app/components/JsonEditor/State.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/components/JsonEditor/State.ts#L121

Added line #L121 was not covered by tests
item: schema,
key: JSON_POINTER_ONE_OF,
parentPath,
required: false,
sortIndex: sortOrder.current.counter,
})
memo[JSONPointer.stringify(item.address)] = item
sortOrder.current.counter += 1
schema.oneOf.forEach((rawItem: any) => {
iterateSchema(rawItem, sortOrder, item.address, memo)

Check warning on line 131 in catalog/app/components/JsonEditor/State.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/components/JsonEditor/State.ts#L128-L131

Added lines #L128 - L131 were not covered by tests
})
}
// TODO: schema.not and schema.allOf

if (!schema.properties) return memo

const requiredKeys = schema.required
Expand Down Expand Up @@ -195,9 +227,14 @@
}

function doesPlaceholderPathMatch(
placeholder: JSONPointer.Path,
placeholderRaw: JSONPointer.Path,
path: JSONPointer.Path,
): boolean {
const placeholder = placeholderRaw.filter(
(item, index, all) =>
index === all.length - 1 ||
(item !== JSON_POINTER_ANY_OF && item !== JSON_POINTER_ONE_OF),
)
if (placeholder.length !== path.length) return false
return placeholder.every(
(item, index) => item === path[index] || item === JSON_POINTER_PLACEHOLDER,
Expand Down Expand Up @@ -382,8 +419,9 @@
children,
errors,
jsonObject,
schema,
schema: schemaWithRefs,

Check warning on line 422 in catalog/app/components/JsonEditor/State.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/components/JsonEditor/State.ts#L422

Added line #L422 was not covered by tests
}: JsonEditorStateProps) {
const schema = JSONSchema.resolveRefs(schemaWithRefs, schemaWithRefs.definitions)

Check warning on line 424 in catalog/app/components/JsonEditor/State.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/components/JsonEditor/State.ts#L424

Added line #L424 was not covered by tests
// NOTE: fieldPath is like URL for editor columns
// `['a', 0, 'b']` means we are focused to `{ a: [ { b: %HERE% }, ... ], ... }`
const [fieldPath, setFieldPath] = React.useState<JSONPointer.Path>([])
Expand Down
134 changes: 67 additions & 67 deletions catalog/app/components/JsonEditor/__snapshots__/State.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1365,10 +1365,10 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*": {
"/longNestedList/__items*": {
"address": [
"longNestedList",
"__*",
"__items*",
],
"required": false,
"sortIndex": 2,
Expand Down Expand Up @@ -1404,11 +1404,11 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*": {
"/longNestedList/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 3,
Expand Down Expand Up @@ -1441,12 +1441,12 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 4,
Expand Down Expand Up @@ -1476,13 +1476,13 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 5,
Expand All @@ -1509,14 +1509,14 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 6,
Expand All @@ -1540,15 +1540,15 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 7,
Expand All @@ -1569,16 +1569,16 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 8,
Expand All @@ -1596,17 +1596,17 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 9,
Expand All @@ -1621,18 +1621,18 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*/__*/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*/__items*/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 10,
Expand All @@ -1644,19 +1644,19 @@ exports[`components/JsonEditor/State iterateSchema should return first value onl
"type": "array",
},
},
"/longNestedList/__*/__*/__*/__*/__*/__*/__*/__*/__*/__*": {
"/longNestedList/__items*/__items*/__items*/__items*/__items*/__items*/__items*/__items*/__items*/__items*": {
"address": [
"longNestedList",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
"__items*",
],
"required": false,
"sortIndex": 11,
Expand Down Expand Up @@ -2312,7 +2312,7 @@ exports[`components/JsonEditor/State iterateSchema should return values for ever
"type": "array",
},
},
"/a/b/c/d/e/f/g/h/i/j/k/testMaxItems/__*": {
"/a/b/c/d/e/f/g/h/i/j/k/testMaxItems/__items*": {
"address": [
"a",
"b",
Expand All @@ -2326,7 +2326,7 @@ exports[`components/JsonEditor/State iterateSchema should return values for ever
"j",
"k",
"testMaxItems",
"__*",
"__items*",
],
"required": false,
"sortIndex": 24,
Expand Down
6 changes: 5 additions & 1 deletion catalog/app/components/JsonEditor/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ export const COLUMN_IDS = {

export const EMPTY_VALUE = Symbol('empty')

export const JSON_POINTER_PLACEHOLDER = '__*'
export const JSON_POINTER_PLACEHOLDER = '__items*'

export const JSON_POINTER_ANY_OF = '__anyOf*'

export const JSON_POINTER_ONE_OF = '__oneOf*'
49 changes: 47 additions & 2 deletions catalog/app/utils/JSONSchema/JSONSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@

if (!isSchemaCompound(optSchema)) return false

return optSchema[condition]!.filter((s: JsonSchema) => s.type || s.$ref).some(
(subSchema: JsonSchema) => doesTypeMatchSchema(value, subSchema),
return optSchema[condition]!.some((subSchema: JsonSchema) =>
doesTypeMatchSchema(value, subSchema),

Check warning on line 168 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L167-L168

Added lines #L167 - L168 were not covered by tests
)
}

Expand Down Expand Up @@ -327,3 +327,48 @@
export function makeSchemaDefaultsSetter(optSchema?: JsonSchema) {
return (obj: any) => scanSchemaAndPrefillValues(getDefaultValue, obj, optSchema)
}

export function resolveRefs(schema: any, definitions: any) {
const result: Record<string, any> = {}

Check warning on line 332 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L332

Added line #L332 was not covered by tests
if (Array.isArray(schema)) {
return schema.map((value): any => {

Check warning on line 334 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L334

Added line #L334 was not covered by tests
if (value.$ref) {
const defKey = value.$ref.split('/').pop()

Check warning on line 336 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L336

Added line #L336 was not covered by tests
if (defKey) {
if (typeof definitions[defKey] === 'object') {
return resolveRefs(definitions[defKey], definitions)
} else {
return definitions[defKey]

Check warning on line 341 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L339-L341

Added lines #L339 - L341 were not covered by tests
}
}
} else {

Check warning on line 344 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L344

Added line #L344 was not covered by tests
if (typeof value === 'object') {
return resolveRefs(value, definitions)
} else {
return value

Check warning on line 348 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L346-L348

Added lines #L346 - L348 were not covered by tests
}
}
})
}

Object.entries(schema).forEach(([key, value]: [any, any]) => {

Check warning on line 354 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L354

Added line #L354 was not covered by tests
if (key === 'definitions') return
if (value.$ref) {
const defKey = value.$ref.split('/').pop()

Check warning on line 357 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L357

Added line #L357 was not covered by tests
if (defKey) {
if (typeof definitions[defKey] === 'object') {
result[key] = resolveRefs(definitions[defKey], definitions)
} else {
result[key] = definitions[defKey]

Check warning on line 362 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L360-L362

Added lines #L360 - L362 were not covered by tests
}
}
} else {

Check warning on line 365 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L365

Added line #L365 was not covered by tests
if (typeof value === 'object') {
result[key] = resolveRefs(value, definitions)
} else {
result[key] = value

Check warning on line 369 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L367-L369

Added lines #L367 - L369 were not covered by tests
}
}
})
return result

Check warning on line 373 in catalog/app/utils/JSONSchema/JSONSchema.ts

View check run for this annotation

Codecov / codecov/patch/informational

catalog/app/utils/JSONSchema/JSONSchema.ts#L373

Added line #L373 was not covered by tests
}
Loading