diff --git a/types/json-schema-merge-allof/index.d.ts b/types/json-schema-merge-allof/index.d.ts new file mode 100644 index 0000000000..3e3c27a13f --- /dev/null +++ b/types/json-schema-merge-allof/index.d.ts @@ -0,0 +1,198 @@ +// Type definitions for json-schema-merge-allof 0.6 +// Project: https://github.com/mokkabonna/json-schema-merge-allof#readme +// Definitions by: Emily Marigold Klassen +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +import { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema'; + +export = merger; + +type JSONSchema = JSONSchema4 | JSONSchema6 | JSONSchema7; +type JSONSchema46 = JSONSchema4 | JSONSchema6; + +declare function merger(rootSchema: T, options: merger.Options & { ignoreAdditionalProperties: true }): T; +declare function merger(rootSchema: JSONSchema4, options?: merger.Options): JSONSchema4; +declare function merger(rootSchema: JSONSchema6, options?: merger.Options): JSONSchema6; +declare function merger(rootSchema: JSONSchema7, options?: merger.Options): JSONSchema7; +declare function merger(rootSchema: JSONSchema46, options?: merger.Options): JSONSchema46; +declare function merger(rootSchema: JSONSchema, options?: merger.Options): JSONSchema; + +declare namespace merger { + interface Options { + /** + * **ignoreAdditionalProperties** default **false** + * + * Allows you to combine schema properties even though some schemas have + * `additionalProperties: false` This is the most common issue people + * face when trying to expand schemas using allOf and a limitation of + * the json schema spec. Be aware though that the schema produced will + * allow more than the original schema. But this is useful if just want + * to combine schemas using allOf as if additionalProperties wasn't + * false during the merge process. The resulting schema will still get + * additionalProperties set to false. + */ + ignoreAdditionalProperties?: boolean; + /** + * **resolvers** Object + * + * Override any default resolver like this: + * + * ```js + * mergeAllOf(schema, { + * resolvers: { + * title: function(values, path, mergeSchemas, options) { + * // choose what title you want to be used based on the conflicting values + * // resolvers MUST return a value other than undefined + * } + * } + * }) + * ``` + * + * The function is passed: + * + * - **values** an array of the conflicting values that need to be + * resolved + * - **path** an array of strings containing the path to the position in + * the schema that caused the resolver to be called (useful if you use + * the same resolver for multiple keywords, or want to implement + * specific logic for custom paths) + * - **mergeSchemas** a function you can call that merges an array of + * schemas + * - **options** the options mergeAllOf was called with + */ + resolvers?: Partial> & { + /** + * ### Default resolver + * You can set a default resolver that catches any unknown keyword. + * Let's say you want to use the same strategy as the ones for the + * meta keywords, to use the first value found. You can accomplish + * that like this: + * + * ```js + * mergeJsonSchema({ + * ... + * }, { + * resolvers: { + * defaultResolver: mergeJsonSchema.options.resolvers.title + * } + * }) + * ``` + */ + defaultResolver?(values: any[], path: string[], mergeSchemas: MergeSchemas, options: Options): any; + }; + } + type MergeSchemas = (schemas: ReadonlyArray) => T; + type MergeChildSchemas = (schemas: ReadonlyArray, childSchemaName: string) => T; + + interface Resolvers { + $id( + values: Array['$id']>, + path: string[], + mergeSchemas: MergeSchemas, + options: Options, + ): NonNullable['$id']>; + $ref(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + $schema(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + additionalItems(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + additionalProperties(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + anyOf(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + contains( + values: Array['contains']>, + path: string[], + mergeSchemas: MergeSchemas, + options: Options, + ): NonNullable['contains']>; + default(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + definitions(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + dependencies(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + description(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + enum(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + examples( + values: Array['examples']>, + path: string[], + mergeSchemas: MergeSchemas, + options: Options, + ): NonNullable['examples']>; + exclusiveMaximum(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + exclusiveMinimum(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + items(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + maxItems(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + maxLength(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + maxProperties(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + maximum(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + minItems(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + minLength(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + minProperties(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + minimum(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + multipleOf(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + not(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + oneOf(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + pattern(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + /** + * ### Combined resolvers + * No separate resolver is called for patternProperties and + * additionalProperties, only the properties resolver is called. Same + * for additionalItems, only items resolver is called. This is because + * those keywords need to be resolved together as they affect each + * other. + * + * Those two resolvers are expected to return an object containing the + * resolved values of all the associated keywords. The keys must be the + * name of the keywords. So the properties resolver need to return an + * object like this containing the resolved values for each keyword: + * + * ```js + * { + * properties: ..., + * patternProperties: ..., + * additionalProperties: ..., + * } + * ``` + * + * Also the resolve function is not passed **mergeSchemas**, but an + * object **mergers** that contains mergers for each of the related + * keywords. So properties get passed an object like this: + * + * ```js + * var mergers = { + * properties: function mergeSchemas(schemas, childSchemaName){...}, + * patternProperties: function mergeSchemas(schemas, childSchemaName){...}, + * additionalProperties: function mergeSchemas(schemas){...}, + * } + * ``` + * + * Some of the mergers requires you to supply a string of the name or + * index of the subschema you are currently merging. This is to make + * sure the path passed to child resolvers are correct. + */ + properties( + values: Schema[], + path: string[], + mergers: { + properties: MergeChildSchemas; + patternProperties: MergeChildSchemas; + additionalProperties: MergeSchemas; + }, + options: Options, + ): Pick; + propertyNames( + values: Array['propertyNames']>, + path: string[], + mergeSchemas: MergeSchemas, + options: Options, + ): NonNullable['propertyNames']>; + required( + values: Array, + path: string[], + mergeSchemas: MergeSchemas, + options: Options, + ): NonNullable; + title(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + type(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + uniqueItems(values: Array, path: string[], mergeSchemas: MergeSchemas, options: Options): NonNullable; + } + const options: { + resolvers: Resolvers; + }; +} diff --git a/types/json-schema-merge-allof/json-schema-merge-allof-tests.ts b/types/json-schema-merge-allof/json-schema-merge-allof-tests.ts new file mode 100644 index 0000000000..9c6b3013dd --- /dev/null +++ b/types/json-schema-merge-allof/json-schema-merge-allof-tests.ts @@ -0,0 +1,28 @@ +import mergeAllOf = require('json-schema-merge-allof'); +import { JSONSchema4, JSONSchema6 } from 'json-schema'; + +type $RefParser_JSONSchema = JSONSchema4 | JSONSchema6; + +const schema: $RefParser_JSONSchema = { type: 'string' }; + +mergeAllOf(schema); + +type JSONSchemaExtra = JSONSchema6 & { + [key: string]: any; +}; + +const schemaExtra: JSONSchemaExtra = { type: 'string' }; + +// $ExpectType JSONSchema6 +mergeAllOf(schemaExtra); + +// $ExpectType JSONSchemaExtra +mergeAllOf(schemaExtra, { ignoreAdditionalProperties: true, resolvers: { + oneOf(values, path, mergeSchemas, options) { + // $ExpectType (JSONSchema6Definition[] | undefined)[] + values; + // $ExpectType Options + options; + return values.reduce((prev, next) => (prev || []).concat(next || []))!; + } +} }); diff --git a/types/json-schema-merge-allof/tsconfig.json b/types/json-schema-merge-allof/tsconfig.json new file mode 100644 index 0000000000..a3b30b41d7 --- /dev/null +++ b/types/json-schema-merge-allof/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "json-schema-merge-allof-tests.ts" + ] +} diff --git a/types/json-schema-merge-allof/tslint.json b/types/json-schema-merge-allof/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/json-schema-merge-allof/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }