Skip to content
Merged
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
92 changes: 80 additions & 12 deletions packages/core/src/mappers/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,25 @@ export const createDefaultValue = (
schema: JsonSchema,
rootSchema: JsonSchema
) => {
const resolvedSchema = Resolve.schema(schema, schema.$ref, rootSchema);
const defaultValue = doCreateDefaultValue(schema, rootSchema);

// preserve the backward compatibility where it is returning an empty object if we can't determine the default value
return defaultValue === undefined ? {} : defaultValue;
};

/**
* Create a default value based on the given schema.
* @param schema the schema for which to create a default value.
* @returns the default value to use, undefined if none was found
*/
export const doCreateDefaultValue = (
schema: JsonSchema,
rootSchema: JsonSchema
) => {
const resolvedSchema =
typeof schema.$ref === 'string'
? Resolve.schema(rootSchema, schema.$ref, rootSchema)
: schema;
if (resolvedSchema.default !== undefined) {
return extractDefaults(resolvedSchema, rootSchema);
}
Expand All @@ -183,22 +201,56 @@ export const createDefaultValue = (
return convertDateToString(new Date(), resolvedSchema.format);
}
return '';
} else if (
hasType(resolvedSchema, 'integer') ||
hasType(resolvedSchema, 'number')
) {
}
if (hasType(resolvedSchema, 'integer') || hasType(resolvedSchema, 'number')) {
return 0;
} else if (hasType(resolvedSchema, 'boolean')) {
}
if (hasType(resolvedSchema, 'boolean')) {
return false;
} else if (hasType(resolvedSchema, 'array')) {
}
if (hasType(resolvedSchema, 'array')) {
return [];
} else if (hasType(resolvedSchema, 'object')) {
}
if (hasType(resolvedSchema, 'object')) {
return extractDefaults(resolvedSchema, rootSchema);
} else if (hasType(resolvedSchema, 'null')) {
}
if (hasType(resolvedSchema, 'null')) {
return null;
} else {
return {};
}

const combinators: CombinatorKeyword[] = ['oneOf', 'anyOf', 'allOf'];
for (const combinator of combinators) {
if (schema[combinator] && Array.isArray(schema[combinator])) {
const combinatorDefault = createDefaultValueForCombinatorSchema(
schema[combinator],
rootSchema
);
if (combinatorDefault !== undefined) {
return combinatorDefault;
}
}
}

// no default value found
return undefined;
};

const createDefaultValueForCombinatorSchema = (
combinatorSchemas: JsonSchema[],
rootSchema: JsonSchema
): any => {
if (combinatorSchemas.length > 0) {
for (const combinatorSchema of combinatorSchemas) {
const result = doCreateDefaultValue(combinatorSchema, rootSchema);
if (result !== undefined) {
// return the first one with type information
return result;
}
}
}

// no default value found
return undefined;
};

/**
Expand All @@ -214,10 +266,26 @@ export const extractDefaults = (schema: JsonSchema, rootSchema: JsonSchema) => {
const resolvedProperty = property.$ref
? Resolve.schema(rootSchema, property.$ref, rootSchema)
: property;
if (resolvedProperty.default !== undefined) {
if (resolvedProperty && resolvedProperty.default !== undefined) {
result[key] = cloneDeep(resolvedProperty.default);
}
}
// there could be more properties in allOf schemas
if (schema.allOf && Array.isArray(schema.allOf)) {
schema.allOf.forEach((allOfSchema) => {
if (allOfSchema && allOfSchema.properties) {
for (const key in allOfSchema.properties) {
const property = allOfSchema.properties[key];
const resolvedProperty = property.$ref
? Resolve.schema(rootSchema, property.$ref, rootSchema)
: property;
if (resolvedProperty && resolvedProperty.default !== undefined) {
result[key] = cloneDeep(resolvedProperty.default);
}
}
}
});
}
return result;
}
return cloneDeep(schema.default);
Expand Down
128 changes: 128 additions & 0 deletions packages/core/test/mappers/renderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,134 @@ test('createDefaultValue', (t) => {
bool: true,
array: ['a', 'b', 'c'],
});

const schemaOneOf: JsonSchema = {
oneOf: [
{
type: 'string',
default: 'oneOfString',
},
{
type: 'number',
default: 42,
},
],
};
const rootSchemaOneOf: JsonSchema = {
definitions: {},
};
const defaultValueOneOf = createDefaultValue(schemaOneOf, rootSchemaOneOf);
t.is(defaultValueOneOf, 'oneOfString');

const schemaAnyOf: JsonSchema = {
anyOf: [
{
type: 'number',
},
{
type: 'string',
default: 'anyOfString',
},
],
};
const rootSchemaAnyOf: JsonSchema = {
definitions: {},
};
const defaultValueAnyOf = createDefaultValue(schemaAnyOf, rootSchemaAnyOf);
t.is(defaultValueAnyOf, 0);

console.log('testcase allof');
const schemaAllOf: JsonSchema = {
allOf: [
{
properties: {
foo: {
type: 'string',
default: 'foo',
},
},
},
{
properties: {
bar: {
type: 'number',
default: 42,
},
},
},
],
};
const rootSchemaAllOf: JsonSchema = {
definitions: {},
};
const defaultValueAllOf = createDefaultValue(schemaAllOf, rootSchemaAllOf);
t.deepEqual(defaultValueAllOf, { foo: 'foo', bar: 42 });

const schemaOneOfEmpty: JsonSchema = {
oneOf: [
{
type: 'string',
},
{
type: 'number',
},
],
};
const rootSchemaOneOfEmpty: JsonSchema = {
definitions: {},
};
const defaultValueOneOfEmpty = createDefaultValue(
schemaOneOfEmpty,
rootSchemaOneOfEmpty
);
t.deepEqual(defaultValueOneOfEmpty, '');

const schemaAnyOfEmpty: JsonSchema = {
anyOf: [
{
type: 'string',
},
{
type: 'number',
},
],
};
const rootSchemaAnyOfEmpty: JsonSchema = {
definitions: {},
};
const defaultValueAnyOfEmpty = createDefaultValue(
schemaAnyOfEmpty,
rootSchemaAnyOfEmpty
);
t.deepEqual(defaultValueAnyOfEmpty, '');

const schemaAllOfEmpty: JsonSchema = {
allOf: [
{
properties: {
foo: {
type: 'string',
},
},
},
{
properties: {
bar: {
type: 'number',
},
},
},
],
};
const rootSchemaAllOfEmpty: JsonSchema = {
definitions: {},
};
const defaultValueAllOfEmpty = createDefaultValue(
schemaAllOfEmpty,
rootSchemaAllOfEmpty
);
console.log('defaultValueAllOfEmpty', defaultValueAllOfEmpty);
t.deepEqual(defaultValueAllOfEmpty, {});
});

test(`mapStateToJsonFormsRendererProps should use registered UI schema given ownProps schema`, (t) => {
Expand Down
Loading