Support specifying top-levels explicitly in TS input
If there are types that have doc comments containing `#TopLevel`, then only those types will be made top-levels.
This commit is contained in:
Родитель
dd3f5e22eb
Коммит
cc1dabedc4
|
@ -46,7 +46,7 @@ function isTypeScriptSource(source: TypeSource): source is TypeScriptTypeSource
|
|||
export interface SchemaTypeSource {
|
||||
kind: "schema";
|
||||
name: string;
|
||||
uri?: string;
|
||||
uris?: string[];
|
||||
schema?: StringInput;
|
||||
}
|
||||
|
||||
|
@ -58,12 +58,8 @@ function toSchemaSource(source: TypeSource): [SchemaTypeSource, boolean] | undef
|
|||
if (isSchemaSource(source)) {
|
||||
return [source, true];
|
||||
} else if (isTypeScriptSource(source)) {
|
||||
return [{
|
||||
kind: "schema",
|
||||
name: "",
|
||||
schema: schemaForTypeScriptSources(source.sources),
|
||||
uri: "#/definitions/"
|
||||
}, false];
|
||||
const { schema, name, uris } = schemaForTypeScriptSources(source.sources);
|
||||
return [{ kind: "schema", name, schema, uris }, false];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
@ -89,7 +85,9 @@ class InputJSONSchemaStore extends JSONSchemaStore {
|
|||
async fetch(address: string): Promise<JSONSchema | undefined> {
|
||||
const maybeInput = this._inputs.get(address);
|
||||
if (maybeInput !== undefined) {
|
||||
return checkJSONSchema(parseJSON(await toString(maybeInput), "JSON Schema", address), () => Ref.root(address));
|
||||
return checkJSONSchema(parseJSON(await toString(maybeInput), "JSON Schema", address), () =>
|
||||
Ref.root(address)
|
||||
);
|
||||
}
|
||||
if (this._delegate === undefined) {
|
||||
return panic(`Schema URI ${address} requested, but no store given`);
|
||||
|
@ -106,8 +104,10 @@ export class InputData {
|
|||
private _schemaInputs: Map<string, StringInput> = Map();
|
||||
private _schemaSources: List<[uri.URI, SchemaTypeSource]> = List();
|
||||
|
||||
constructor(private readonly _compressedJSON: CompressedJSON, private readonly _givenSchemaStore: JSONSchemaStore | undefined) {
|
||||
}
|
||||
constructor(
|
||||
private readonly _compressedJSON: CompressedJSON,
|
||||
private readonly _givenSchemaStore: JSONSchemaStore | undefined
|
||||
) {}
|
||||
|
||||
get jsonInputs(): Map<string, { samples: Value[]; description?: string }> {
|
||||
return Map(this._samples);
|
||||
|
@ -153,32 +153,44 @@ export class InputData {
|
|||
}
|
||||
|
||||
private addSchemaTypeSource(schemaSource: SchemaTypeSource): void {
|
||||
const { uri, schema } = schemaSource;
|
||||
const { uris, schema } = schemaSource;
|
||||
|
||||
let normalizedURI: uri.URI;
|
||||
let normalizedURIs: uri.URI[];
|
||||
const uriPath = `-${this._schemaInputs.size + 1}`;
|
||||
if (uri === undefined) {
|
||||
normalizedURI = new URI(uriPath);
|
||||
if (uris === undefined) {
|
||||
normalizedURIs = [new URI(uriPath)];
|
||||
} else {
|
||||
normalizedURI = new URI(uri).normalize();
|
||||
if (normalizedURI.clone().hash("").toString() === "") {
|
||||
normalizedURI.path(uriPath);
|
||||
}
|
||||
normalizedURIs = uris.map(uri => {
|
||||
const normalizedURI = new URI(uri).normalize();
|
||||
if (
|
||||
normalizedURI
|
||||
.clone()
|
||||
.hash("")
|
||||
.toString() === ""
|
||||
) {
|
||||
normalizedURI.path(uriPath);
|
||||
}
|
||||
return normalizedURI;
|
||||
});
|
||||
}
|
||||
|
||||
if (schema === undefined) {
|
||||
assert(uri !== undefined, "URI must be given if schema source is not specified");
|
||||
assert(uris !== undefined, "URIs must be given if schema source is not specified");
|
||||
} else {
|
||||
this._schemaInputs = this._schemaInputs.set(
|
||||
normalizedURI
|
||||
.clone()
|
||||
.hash("")
|
||||
.toString(),
|
||||
schema
|
||||
);
|
||||
for (const normalizedURI of normalizedURIs) {
|
||||
this._schemaInputs = this._schemaInputs.set(
|
||||
normalizedURI
|
||||
.clone()
|
||||
.hash("")
|
||||
.toString(),
|
||||
schema
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this._schemaSources = this._schemaSources.push([normalizedURI, schemaSource]);
|
||||
for (const normalizedURI of normalizedURIs) {
|
||||
this._schemaSources = this._schemaSources.push([normalizedURI, schemaSource]);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether we need IR for this type source
|
||||
|
@ -191,10 +203,10 @@ export class InputData {
|
|||
if (maybeSchemaSource !== undefined) {
|
||||
const [schemaSource, isDirectInput] = maybeSchemaSource;
|
||||
needIR = isDirectInput || needIR;
|
||||
|
||||
|
||||
this.addSchemaTypeSource(schemaSource);
|
||||
} else {
|
||||
needIR = await this.addOtherTypeSource(source) || needIR;
|
||||
} else {
|
||||
needIR = (await this.addOtherTypeSource(source)) || needIR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as ts from "typescript";
|
||||
import { PartialArgs, CompilerOptions, generateSchema } from "typescript-json-schema";
|
||||
|
||||
import { panic, inflateBase64 } from "./Support";
|
||||
import { panic, inflateBase64, defined } from "./Support";
|
||||
import { encodedDefaultTypeScriptLibrary } from "./EncodedDefaultTypeScriptLibrary";
|
||||
import { ErrorMessage, messageError } from "./Messages";
|
||||
|
||||
|
@ -94,9 +94,15 @@ class CompilerHost implements ts.CompilerHost {
|
|||
}
|
||||
}
|
||||
|
||||
export function schemaForTypeScriptSources(sourceFileNames: string[]): string;
|
||||
export function schemaForTypeScriptSources(sources: { [fileName: string]: string }): string;
|
||||
export function schemaForTypeScriptSources(sources: string[] | { [fileName: string]: string }): string {
|
||||
// FIXME: We're stringifying and then parsing this schema again. Just pass around
|
||||
// the schema directly.
|
||||
export function schemaForTypeScriptSources(sourceFileNames: string[]): { schema: string; name: string; uris: string[] };
|
||||
export function schemaForTypeScriptSources(sources: {
|
||||
[fileName: string]: string;
|
||||
}): { schema: string; name: string; uris: string[] };
|
||||
export function schemaForTypeScriptSources(
|
||||
sources: string[] | { [fileName: string]: string }
|
||||
): { schema: string; name: string; uris: string[] } {
|
||||
let fileNames: string[];
|
||||
let host: ts.CompilerHost;
|
||||
|
||||
|
@ -118,5 +124,47 @@ export function schemaForTypeScriptSources(sources: string[] | { [fileName: stri
|
|||
}
|
||||
|
||||
const schema = generateSchema(program, "*", settings);
|
||||
return JSON.stringify(schema);
|
||||
const uris: string[] = [];
|
||||
let topLevelName: string | undefined = undefined;
|
||||
if (schema !== null && typeof schema === "object" && typeof schema.definitions === "object") {
|
||||
for (const name of Object.getOwnPropertyNames(schema.definitions)) {
|
||||
const definition = schema.definitions[name];
|
||||
if (
|
||||
definition === null ||
|
||||
Array.isArray(definition) ||
|
||||
typeof definition !== "object" ||
|
||||
typeof definition.description !== "string"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const description = definition.description as string;
|
||||
const matches = description.match(/#TopLevel/);
|
||||
if (matches === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const index = defined(matches.index);
|
||||
definition.description = description.substr(0, index) + description.substr(index + matches[0].length);
|
||||
|
||||
uris.push(`#/definitions/${name}`);
|
||||
|
||||
if (topLevelName === undefined) {
|
||||
if (typeof definition.title === "string") {
|
||||
topLevelName = definition.title;
|
||||
} else {
|
||||
topLevelName = name;
|
||||
}
|
||||
} else {
|
||||
topLevelName = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uris.length === 0) {
|
||||
uris.push("#/definitions/");
|
||||
}
|
||||
if (topLevelName === undefined) {
|
||||
topLevelName = "";
|
||||
}
|
||||
return { schema: JSON.stringify(schema), name: topLevelName, uris };
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ async function samplesFromDirectory(dataDir: string): Promise<TypeSource[]> {
|
|||
sourcesInDir.push({
|
||||
kind: "schema",
|
||||
name,
|
||||
uri: fileOrUrl
|
||||
uris: [fileOrUrl]
|
||||
});
|
||||
} else if (file.endsWith(".gqlschema")) {
|
||||
messageAssert(graphQLSchema === undefined, ErrorMessage.DriverMoreThanOneGraphQLSchemaInDir, {
|
||||
|
@ -603,7 +603,7 @@ async function typeSourcesForURIs(name: string, uris: string[], options: CLIOpti
|
|||
case "json":
|
||||
return [await sourceFromFileOrUrlArray(name, uris)];
|
||||
case "schema":
|
||||
return uris.map(uri => ({ kind: "schema", name, uri } as SchemaTypeSource));
|
||||
return uris.map(uri => ({ kind: "schema", name, uris: [uri] } as SchemaTypeSource));
|
||||
default:
|
||||
return panic(`typeSourceForURIs must not be called for source language ${options.srcLang}`);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче