Skip to content

Commit 2594df3

Browse files
committed
Remove json-schema-ref-parser
Removes json-schema-ref-parser and corresponding resolving functionality and dependencies from JSON Forms. Resolving of external dependencies is not a core feature of JSON Forms which is why we delegated it to a 3rd party dependency. However the json-schema-ref-parser library is not only slow and mutating schemas in place but also brings in a number of questionable Node dependent dependencies. The only binding actually using this functionality is the React binding. The way resolving was implemented resulted in the same flow as resolving it outside of JSON Forms and handing the resolved schema over. Based on these downsides and the very little upsides we decided to remove json-schema-ref-parser without a replacement from JSON Forms. Angular and Vue consumers don't need to spend any migration efforts. In @jsonforms/react we still export the backward API compatible 'ResolvedJsonFormsDispatch'. Therefore only React consumers actually using the now removed 'refParserOptions' are forced to migrate while for all other React consumers it depends on their use cases. The built-in resolving mechanism in JSON Forms is quite basic. When the schema was fully resolved anyway the basic resolving did quite fine. However as this is no longer the case by default, there are now cases which are no longer supported and break. This is especially the case for complex combinator use cases involving references. Of course these can still be used when the consumer resolves their schema themselves before handing it over to JSON Forms. We also plan to make our built-in resolving more robust before the full 3.0 release to cover more of these cases. However we will not reach feature parity without major additional efforts.
1 parent b4f70e3 commit 2594df3

33 files changed

+288
-1039
lines changed

package-lock.json

Lines changed: 212 additions & 267 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,7 @@
6363
"dependencies": {
6464
"@types/json-schema": "^7.0.3",
6565
"ajv": "^6.10.2",
66-
"json-schema-ref-parser": "7.1.3",
67-
"lodash": "^4.17.15",
68-
"uri-js": "^4.2.2",
69-
"uuid": "^3.3.3"
66+
"lodash": "^4.17.15"
7067
},
7168
"devDependencies": {
7269
"@istanbuljs/nyc-config-typescript": "0.1.3",

packages/core/src/actions/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { JsonSchema, UISchemaElement } from '../';
2727
import { generateDefaultUISchema, generateJsonSchema } from '../generators';
2828

2929
import { RankedTester } from '../testers';
30-
import RefParser from 'json-schema-ref-parser';
3130
import { UISchemaTester } from '../reducers/uischemas';
3231
import { ValidationMode } from '../reducers/core';
3332

@@ -99,7 +98,6 @@ export interface UpdateCoreAction {
9998

10099
export interface InitActionOptions {
101100
ajv?: AJV.Ajv;
102-
refParserOptions?: RefParser.Options;
103101
validationMode?: ValidationMode;
104102
}
105103

packages/core/src/reducers/core.ts

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import filter from 'lodash/filter';
2929
import isEqual from 'lodash/isEqual';
3030
import isFunction from 'lodash/isFunction';
3131
import { Ajv, ErrorObject, ValidateFunction } from 'ajv';
32-
import RefParser from 'json-schema-ref-parser';
3332
import {
3433
CoreActions,
3534
INIT,
@@ -79,7 +78,6 @@ export interface JsonFormsCore {
7978
errors?: ErrorObject[];
8079
validator?: ValidateFunction;
8180
ajv?: Ajv;
82-
refParserOptions?: RefParser.Options;
8381
validationMode?: ValidationMode;
8482
}
8583

@@ -90,7 +88,6 @@ const initState: JsonFormsCore = {
9088
errors: [],
9189
validator: alwaysValid,
9290
ajv: undefined,
93-
refParserOptions: undefined,
9491
validationMode: 'ValidateAndShow'
9592
};
9693

@@ -107,8 +104,7 @@ const getOrCreateAjv = (state: JsonFormsCore, action?: InitAction | UpdateCoreAc
107104
// options object with ajv
108105
return action.options.ajv;
109106
} else if (
110-
action.options !== undefined &&
111-
!hasRefParserOption(action.options)
107+
action.options !== undefined
112108
) {
113109
// it is not an option object => should be ajv itself => check for compile function
114110
if (isFunction(action.options.compile)) {
@@ -124,23 +120,6 @@ const getOrCreateAjv = (state: JsonFormsCore, action?: InitAction | UpdateCoreAc
124120
return createAjv();
125121
};
126122

127-
const getRefParserOptions = (
128-
state: JsonFormsCore,
129-
action?: InitAction | UpdateCoreAction
130-
): RefParser.Options => {
131-
if (action && hasRefParserOption(action.options)) {
132-
return action.options.refParserOptions;
133-
}
134-
return state.refParserOptions;
135-
};
136-
137-
const hasRefParserOption = (option: any): option is InitActionOptions => {
138-
if (option) {
139-
return option.refParserOptions !== undefined;
140-
}
141-
return false;
142-
};
143-
144123
const hasAjvOption = (option: any): option is InitActionOptions => {
145124
if (option) {
146125
return option.ajv !== undefined;
@@ -173,7 +152,6 @@ export const coreReducer: Reducer<JsonFormsCore, CoreActions> = (
173152
switch (action.type) {
174153
case INIT: {
175154
const thisAjv = getOrCreateAjv(state, action);
176-
const o = getRefParserOptions(state, action);
177155

178156
const validationMode = getValidationMode(state, action);
179157
const v = validationMode === 'NoValidation' ? alwaysValid : thisAjv.compile(action.schema);
@@ -187,13 +165,11 @@ export const coreReducer: Reducer<JsonFormsCore, CoreActions> = (
187165
errors: e,
188166
validator: v,
189167
ajv: thisAjv,
190-
refParserOptions: o,
191168
validationMode
192169
};
193170
}
194171
case UPDATE_CORE: {
195172
const thisAjv = getOrCreateAjv(state, action);
196-
const refParserOptions = getRefParserOptions(state, action);
197173
const validationMode = getValidationMode(state, action);
198174
let validator = state.validator;
199175
let errors = state.errors;
@@ -219,7 +195,6 @@ export const coreReducer: Reducer<JsonFormsCore, CoreActions> = (
219195
state.ajv !== thisAjv ||
220196
state.errors !== errors ||
221197
state.validator !== validator ||
222-
state.refParserOptions !== refParserOptions ||
223198
state.validationMode !== validationMode;
224199
return stateChanged
225200
? {
@@ -230,7 +205,6 @@ export const coreReducer: Reducer<JsonFormsCore, CoreActions> = (
230205
ajv: thisAjv === state.ajv ? state.ajv : thisAjv,
231206
errors: isEqual(errors, state.errors) ? state.errors : errors,
232207
validator: validator === state.validator ? state.validator : validator,
233-
refParserOptions: refParserOptions === state.refParserOptions ? state.refParserOptions : refParserOptions,
234208
validationMode: validationMode === state.validationMode ? state.validationMode : validationMode
235209
}
236210
: state;
@@ -402,6 +376,3 @@ export const errorAt = (instancePath: string, schema: JsonSchema) =>
402376
getErrorsAt(instancePath, schema, path => path === instancePath);
403377
export const subErrorsAt = (instancePath: string, schema: JsonSchema) =>
404378
getErrorsAt(instancePath, schema, path => path.startsWith(instancePath));
405-
406-
export const extractRefParserOptions = (state: JsonFormsCore) =>
407-
get(state, 'refParserOptions');

packages/core/src/reducers/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import {
2929
errorsAt,
3030
extractAjv,
3131
extractData,
32-
extractRefParserOptions,
3332
extractSchema,
3433
extractUiSchema,
3534
JsonFormsCore,
@@ -59,7 +58,6 @@ import {
5958
import { Generate } from '../generators';
6059
import { JsonFormsCellRendererRegistryEntry } from './cells';
6160
import { JsonSchema } from '../models/jsonSchema';
62-
import RefParser from 'json-schema-ref-parser';
6361

6462
import { cellReducer } from './cells';
6563
import { configReducer } from './config';
@@ -95,8 +93,6 @@ export const getSchema = (state: JsonFormsState): JsonSchema =>
9593
extractSchema(get(state, 'jsonforms.core'));
9694
export const getUiSchema = (state: JsonFormsState): UISchemaElement =>
9795
extractUiSchema(get(state, 'jsonforms.core'));
98-
export const getRefParserOptions = (state: JsonFormsState): RefParser.Options =>
99-
extractRefParserOptions(get(state, 'jsonforms.core'));
10096
export const getAjv = (
10197
state: JsonFormsState
10298
): Ajv => extractAjv(get(state, 'jsonforms.core'));

packages/core/src/util/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,6 @@ const Resolve: {
115115
export {
116116
resolveData,
117117
resolveSchema,
118-
findRefs,
119-
SchemaRef,
120-
SchemaRefs
121118
} from './resolvers';
122119
export { Resolve };
123120

packages/core/src/util/renderer.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@ import get from 'lodash/get';
2626
import { ControlElement, UISchemaElement } from '../models/uischema';
2727
import union from 'lodash/union';
2828
import find from 'lodash/find';
29-
import RefParser from 'json-schema-ref-parser';
3029
import {
3130
findUISchema,
3231
getAjv,
3332
getCells,
3433
getConfig,
3534
getData,
3635
getErrorAt,
37-
getRefParserOptions,
3836
getRenderers,
3937
getSchema,
4038
getSubErrorsAt,
@@ -805,7 +803,6 @@ export interface OwnPropsOfJsonFormsRenderer extends OwnPropsOfRenderer {}
805803
export interface StatePropsOfJsonFormsRenderer
806804
extends OwnPropsOfJsonFormsRenderer {
807805
rootSchema: JsonSchema;
808-
refResolver: any;
809806
}
810807

811808
export interface JsonFormsProps extends StatePropsOfJsonFormsRenderer {}
@@ -834,8 +831,6 @@ export const mapStateToJsonFormsRendererProps = (
834831
schema: ownProps.schema || getSchema(state),
835832
rootSchema: getSchema(state),
836833
uischema: uischema,
837-
refResolver: (schema: any) =>
838-
RefParser.dereference(schema, getRefParserOptions(state)),
839834
path: ownProps.path
840835
};
841836
};
@@ -892,12 +887,19 @@ const mapStateToCombinatorRendererProps = (
892887
);
893888
};
894889
let indexOfFittingSchema: number;
890+
// TODO instead of compiling the combinator subschemas we can compile the original schema
891+
// without the combinator alternatives and then revalidate and check the errors for the
892+
// element
895893
for (let i = 0; i < _schema[keyword].length; i++) {
896-
const valFn = ajv.compile(_schema[keyword][i]);
897-
valFn(data);
898-
if (dataIsValid(valFn.errors)) {
899-
indexOfFittingSchema = i;
900-
break;
894+
try {
895+
const valFn = ajv.compile(_schema[keyword][i]);
896+
valFn(data);
897+
if (dataIsValid(valFn.errors)) {
898+
indexOfFittingSchema = i;
899+
break;
900+
}
901+
} catch (error) {
902+
console.debug("Combinator subschema is not self contained, can't hand it over to AJV");
901903
}
902904
}
903905

0 commit comments

Comments
 (0)