Merge pull request #968 from quicktype/additional-schemas

Allow adding additional schemas for $id.  Fixes #967
This commit is contained in:
Mark Probst 2018-07-17 22:00:26 +02:00 коммит произвёл GitHub
Родитель 5f686d6358 7fefd37b36
Коммит f73c63229a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 46 добавлений и 11 удалений

Просмотреть файл

@ -56,6 +56,7 @@ export interface CLIOptions {
src: string[];
srcUrls?: string;
srcLang: string;
additionalSchema: string[];
graphqlSchema?: string;
graphqlIntrospect?: string;
httpHeader?: string[];
@ -275,6 +276,7 @@ function inferCLIOptions(opts: Partial<CLIOptions>, targetLanguage: TargetLangua
version: opts.version || false,
out: opts.out,
buildMarkovChain: opts.buildMarkovChain,
additionalSchema: opts.additionalSchema || [],
graphqlSchema: opts.graphqlSchema,
graphqlIntrospect: opts.graphqlIntrospect,
httpMethod: opts.httpMethod,
@ -397,6 +399,14 @@ function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinit
typeLabel: "HEADER",
description: "HTTP header for the GraphQL introspection query."
},
{
name: "additional-schema",
alias: "S",
type: String,
multiple: true,
typeLabel: "FILE",
description: "Register the $id's of additional JSON Schema files."
},
{
name: "no-render",
type: Boolean,
@ -644,7 +654,11 @@ function makeTypeScriptSource(fileNames: string[]): SchemaTypeSource {
return Object.assign({ kind: "schema" }, schemaForTypeScriptSources(sources)) as SchemaTypeSource;
}
async function makeInputData(sources: TypeSource[], targetLanguage: TargetLanguage): Promise<InputData> {
async function makeInputData(
sources: TypeSource[],
targetLanguage: TargetLanguage,
additionalSchemaAddresses: ReadonlyArray<string>
): Promise<InputData> {
const inputData = new InputData();
for (const source of sources) {
@ -656,7 +670,11 @@ async function makeInputData(sources: TypeSource[], targetLanguage: TargetLangua
await inputData.addSource("json", source, () => jsonInputForTargetLanguage(targetLanguage));
break;
case "schema":
await inputData.addSource("schema", source, () => new JSONSchemaInput(new FetchingJSONSchemaStore()));
await inputData.addSource(
"schema",
source,
() => new JSONSchemaInput(new FetchingJSONSchemaStore(), [], additionalSchemaAddresses)
);
break;
default:
return assertNever(source);
@ -800,7 +818,7 @@ export async function makeQuicktypeOptions(
return messageError("DriverUnknownOutputLanguage", { lang: options.lang });
}
const inputData = await makeInputData(sources, lang);
const inputData = await makeInputData(sources, lang, options.additionalSchema);
const quicktypeOptions: Partial<Options> = {
lang,

Просмотреть файл

@ -39,6 +39,7 @@ export type ErrorProperties =
| { kind: "SchemaKeyNotInObject"; properties: { key: string; ref: Ref } }
| { kind: "SchemaFetchError"; properties: { address: string; base: Ref } }
| { kind: "SchemaFetchErrorTopLevel"; properties: { address: string } }
| { kind: "SchemaFetchErrorAdditional"; properties: { address: string } }
// GraphQL input
| { kind: "GraphQLNoQueriesDefined"; properties: {} }
@ -110,8 +111,9 @@ const errorMessages: ErrorMessages = {
"Trying to index array in schema with key that is not a number, but is ${actual} at ${ref}",
SchemaIndexNotInArray: "Index ${index} out of range of schema array at ${ref}",
SchemaKeyNotInObject: "Key ${key} not in schema object at ${ref}",
SchemaFetchError: "Could not fetch schema ${address}, referred to from ${base}: ${error}",
SchemaFetchErrorTopLevel: "Could not fetch top-level schema ${address}: ${error}",
SchemaFetchError: "Could not fetch schema ${address}, referred to from ${base}",
SchemaFetchErrorTopLevel: "Could not fetch top-level schema ${address}",
SchemaFetchErrorAdditional: "Could not fetch additional schema ${address}",
// GraphQL input
GraphQLNoQueriesDefined: "GraphQL file doesn't have any queries defined.",

Просмотреть файл

@ -161,7 +161,6 @@ export class JSONSchemaInput implements Input<JSONSchemaSourceData> {
readonly kind: string = "schema";
readonly needSchemaProcessing: boolean = true;
private _schemaStore: JSONSchemaStore | undefined = undefined;
private readonly _attributeProducers: JSONSchemaAttributeProducer[];
private readonly _schemaInputs: Map<string, StringInput> = new Map();
@ -172,10 +171,10 @@ export class JSONSchemaInput implements Input<JSONSchemaSourceData> {
private _needIR: boolean = false;
constructor(
givenSchemaStore: JSONSchemaStore | undefined,
additionalAttributeProducers: JSONSchemaAttributeProducer[] = []
private _schemaStore: JSONSchemaStore | undefined,
additionalAttributeProducers: JSONSchemaAttributeProducer[] = [],
private readonly _additionalSchemaAddresses: ReadonlyArray<string> = []
) {
this._schemaStore = givenSchemaStore;
this._attributeProducers = [descriptionAttributeProducer, accessorNamesAttributeProducer].concat(
additionalAttributeProducers
);
@ -190,7 +189,14 @@ export class JSONSchemaInput implements Input<JSONSchemaSourceData> {
}
async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise<void> {
await addTypesInSchema(ctx, typeBuilder, defined(this._schemaStore), this._topLevels, this._attributeProducers);
await addTypesInSchema(
ctx,
typeBuilder,
defined(this._schemaStore),
this._topLevels,
this._attributeProducers,
this._additionalSchemaAddresses
);
}
async addSource(schemaSource: JSONSchemaSourceData): Promise<void> {

Просмотреть файл

@ -493,7 +493,8 @@ export async function addTypesInSchema(
typeBuilder: TypeBuilder,
store: JSONSchemaStore,
references: ReadonlyMap<string, Ref>,
attributeProducers: JSONSchemaAttributeProducer[]
attributeProducers: JSONSchemaAttributeProducer[],
additionalSchemaAddresses: ReadonlyArray<string>
): Promise<void> {
const canonizer = new Canonizer(ctx);
@ -894,6 +895,14 @@ export async function addTypesInSchema(
return result;
}
for (const address of additionalSchemaAddresses) {
const schema = await store.get(address, ctx.debugPrintSchemaResolving);
if (schema === undefined) {
return messageError("SchemaFetchErrorAdditional", { address });
}
canonizer.addSchema(schema, address);
}
for (const [topLevelName, topLevelRef] of references) {
const [target, loc] = await resolveVirtualRef(
new Location(new Ref(topLevelRef.addressURI, [])),