Add a TypeScript TypeSource (#727)
This commit is contained in:
Родитель
43b66b5f0c
Коммит
68e6f8577d
15
package.json
15
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "quicktype",
|
||||
"version": "9.0.0",
|
||||
"version": "10.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
@ -69,9 +69,7 @@
|
|||
"uglify-js": "^3.0.26",
|
||||
"watch": "^1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"dist/**"
|
||||
],
|
||||
"files": ["dist/**"],
|
||||
"bin": "dist/cli/index.js",
|
||||
"jest": {
|
||||
"transform": {
|
||||
|
@ -83,13 +81,6 @@
|
|||
}
|
||||
},
|
||||
"testRegex": "(/__tests__/.*)\\.test\\.(tsx?)$",
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"jsx",
|
||||
"json",
|
||||
"node"
|
||||
]
|
||||
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export function sourcesFromPostmanCollection(
|
|||
}
|
||||
}
|
||||
if (samples.length > 0) {
|
||||
const source: JSONTypeSource = { name: c.name, samples };
|
||||
const source: JSONTypeSource = { kind: "json", name: c.name, samples };
|
||||
const sourceDescription = [c.name];
|
||||
|
||||
if (typeof c.request === "object") {
|
||||
|
|
|
@ -11,14 +11,13 @@ import {
|
|||
getTargetLanguage,
|
||||
TypeSource,
|
||||
GraphQLTypeSource,
|
||||
isJSONSource,
|
||||
StringInput,
|
||||
SchemaTypeSource,
|
||||
isSchemaSource,
|
||||
quicktypeMultiFile,
|
||||
SerializedRenderResult,
|
||||
TargetLanguage,
|
||||
languageNamed
|
||||
languageNamed,
|
||||
TypeScriptTypeSource
|
||||
} from "..";
|
||||
|
||||
import { OptionDefinition } from "../RendererOptions";
|
||||
|
@ -79,7 +78,7 @@ const defaultDefaultTargetLanguageName: string = "go";
|
|||
|
||||
async function sourceFromFileOrUrlArray(name: string, filesOrUrls: string[]): Promise<JSONTypeSource> {
|
||||
const samples = await Promise.all(filesOrUrls.map(readableFromFileOrURL));
|
||||
return { name, samples };
|
||||
return { kind: "json", name, samples };
|
||||
}
|
||||
|
||||
function typeNameFromFilename(filename: string): string {
|
||||
|
@ -109,14 +108,14 @@ async function samplesFromDirectory(dataDir: string, topLevelRefs: string[] | un
|
|||
}
|
||||
|
||||
if (file.endsWith(".url") || file.endsWith(".json")) {
|
||||
// FIXME: Why do we include the URI here?
|
||||
sourcesInDir.push({
|
||||
kind: "json",
|
||||
name,
|
||||
uri: fileOrUrl,
|
||||
samples: [await readableFromFileOrURL(fileOrUrl)]
|
||||
});
|
||||
} else if (file.endsWith(".schema")) {
|
||||
sourcesInDir.push({
|
||||
kind: "schema",
|
||||
name,
|
||||
uri: fileOrUrl,
|
||||
topLevelRefs
|
||||
|
@ -125,7 +124,12 @@ async function samplesFromDirectory(dataDir: string, topLevelRefs: string[] | un
|
|||
assert(graphQLSchema === undefined, `More than one GraphQL schema in ${dataDir}`);
|
||||
graphQLSchema = await readableFromFileOrURL(fileOrUrl);
|
||||
} else if (file.endsWith(".graphql")) {
|
||||
graphQLSources.push({ name, schema: undefined, query: await readableFromFileOrURL(fileOrUrl) });
|
||||
graphQLSources.push({
|
||||
kind: "graphql",
|
||||
name,
|
||||
schema: undefined,
|
||||
query: await readableFromFileOrURL(fileOrUrl)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,25 +156,39 @@ async function samplesFromDirectory(dataDir: string, topLevelRefs: string[] | un
|
|||
let jsonSamples: StringInput[] = [];
|
||||
const schemaSources: SchemaTypeSource[] = [];
|
||||
const graphQLSources: GraphQLTypeSource[] = [];
|
||||
const typeScriptSources: TypeScriptTypeSource[] = [];
|
||||
|
||||
for (const source of await readFilesOrURLsInDirectory(dir)) {
|
||||
// FIXME: We do a type switch here, but we know which types we're putting in
|
||||
// in the function above. It should separate it right away.
|
||||
if (isJSONSource(source)) {
|
||||
jsonSamples = jsonSamples.concat(source.samples);
|
||||
} else if (isSchemaSource(source)) {
|
||||
schemaSources.push(source);
|
||||
} else {
|
||||
graphQLSources.push(source);
|
||||
switch (source.kind) {
|
||||
case "json":
|
||||
jsonSamples = jsonSamples.concat(source.samples);
|
||||
break;
|
||||
case "schema":
|
||||
schemaSources.push(source);
|
||||
break;
|
||||
case "graphql":
|
||||
graphQLSources.push(source);
|
||||
break;
|
||||
case "typescript":
|
||||
typeScriptSources.push(source);
|
||||
break;
|
||||
default:
|
||||
return panic("Unrecognized source");
|
||||
}
|
||||
}
|
||||
if (jsonSamples.length > 0 && schemaSources.length + graphQLSources.length > 0) {
|
||||
return panic("Cannot mix JSON samples with JSON Schema or GraphQL in input subdirectory");
|
||||
|
||||
if (jsonSamples.length > 0 && schemaSources.length + graphQLSources.length + typeScriptSources.length > 0) {
|
||||
return panic("Cannot mix JSON samples with JSON Schems, GraphQL, or TypeScript in input subdirectory");
|
||||
}
|
||||
if (schemaSources.length > 0 && graphQLSources.length > 0) {
|
||||
return panic("Cannot mix JSON Schema with GraphQL in an input subdirectory");
|
||||
|
||||
const oneUnlessEmpty = (xs: any[]) => Math.sign(xs.length);
|
||||
if (oneUnlessEmpty(schemaSources) + oneUnlessEmpty(graphQLSources) + oneUnlessEmpty(typeScriptSources) > 1) {
|
||||
return panic("Cannot mix JSON Schema, GraphQL, and TypeScript in an input subdirectory");
|
||||
}
|
||||
|
||||
if (jsonSamples.length > 0) {
|
||||
sources.push({
|
||||
kind: "json",
|
||||
name: path.basename(dir),
|
||||
samples: jsonSamples
|
||||
});
|
||||
|
@ -597,7 +615,7 @@ async function typeSourceForURIs(name: string, uris: string[], options: CLIOptio
|
|||
return await sourceFromFileOrUrlArray(name, uris);
|
||||
case "schema":
|
||||
assert(uris.length === 1, `Must have exactly one schema for ${name}`);
|
||||
return { name, uri: uris[0], topLevelRefs: topLevelRefsForOptions(options) };
|
||||
return { kind: "schema", name, uri: uris[0], topLevelRefs: topLevelRefsForOptions(options) };
|
||||
default:
|
||||
return panic(`typeSourceForURIs must not be called for source language ${options.srcLang}`);
|
||||
}
|
||||
|
@ -682,7 +700,7 @@ export async function makeQuicktypeOptions(
|
|||
const schema = JSON.parse(schemaString);
|
||||
const query = await readableFromFileOrURL(queryFile);
|
||||
const name = numSources === 1 ? options.topLevel : typeNameFromFilename(queryFile);
|
||||
gqlSources.push({ name, schema, query });
|
||||
gqlSources.push({ kind: "graphql", name, schema, query });
|
||||
}
|
||||
sources = gqlSources;
|
||||
break;
|
||||
|
@ -691,8 +709,10 @@ export async function makeQuicktypeOptions(
|
|||
sources = await getSources(options);
|
||||
break;
|
||||
case "typescript":
|
||||
// TODO make this a TypeScriptSource
|
||||
sources = [
|
||||
{
|
||||
kind: "schema",
|
||||
name: options.topLevel,
|
||||
schema: schemaForTypeScriptSources(options.src),
|
||||
topLevelRefs: ["/definitions/"]
|
||||
|
|
46
src/index.ts
46
src/index.ts
|
@ -24,6 +24,7 @@ import { descriptionTypeAttributeKind } from "./TypeAttributes";
|
|||
import { flattenUnions } from "./FlattenUnions";
|
||||
import { resolveIntersections } from "./ResolveIntersections";
|
||||
import { replaceObjectType } from "./ReplaceObjectType";
|
||||
import { schemaForTypeScriptSources } from "./TypeScriptInput";
|
||||
|
||||
// Re-export essential types and functions
|
||||
export { TargetLanguage } from "./TargetLanguage";
|
||||
|
@ -49,16 +50,27 @@ export type RendererOptions = { [name: string]: string };
|
|||
export type StringInput = string | Readable;
|
||||
|
||||
export interface JSONTypeSource {
|
||||
kind: "json";
|
||||
name: string;
|
||||
samples: StringInput[];
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function isJSONSource(source: TypeSource): source is JSONTypeSource {
|
||||
return "samples" in source;
|
||||
return source.kind === "json";
|
||||
}
|
||||
|
||||
export interface TypeScriptTypeSource {
|
||||
kind: "typescript";
|
||||
sources: { [filename: string]: string };
|
||||
}
|
||||
|
||||
export function isTypeScriptSource(source: TypeSource): source is TypeScriptTypeSource {
|
||||
return source.kind === "typescript";
|
||||
}
|
||||
|
||||
export interface SchemaTypeSource {
|
||||
kind: "schema";
|
||||
name: string;
|
||||
uri?: string;
|
||||
schema?: StringInput;
|
||||
|
@ -66,20 +78,35 @@ export interface SchemaTypeSource {
|
|||
}
|
||||
|
||||
export function isSchemaSource(source: TypeSource): source is SchemaTypeSource {
|
||||
return !("query" in source) && !("samples" in source);
|
||||
return source.kind === "schema";
|
||||
}
|
||||
|
||||
export function toSchemaSource(source: TypeSource): SchemaTypeSource | undefined {
|
||||
if (isSchemaSource(source)) {
|
||||
return source;
|
||||
} else if (isTypeScriptSource(source)) {
|
||||
return {
|
||||
kind: "schema",
|
||||
name: "",
|
||||
schema: schemaForTypeScriptSources(source.sources),
|
||||
topLevelRefs: ["/definitions/"]
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface GraphQLTypeSource {
|
||||
kind: "graphql";
|
||||
name: string;
|
||||
schema: any;
|
||||
query: StringInput;
|
||||
}
|
||||
|
||||
export function isGraphQLSource(source: TypeSource): source is GraphQLTypeSource {
|
||||
return "query" in source;
|
||||
return source.kind === "graphql";
|
||||
}
|
||||
|
||||
export type TypeSource = GraphQLTypeSource | JSONTypeSource | SchemaTypeSource;
|
||||
export type TypeSource = GraphQLTypeSource | JSONTypeSource | SchemaTypeSource | TypeScriptTypeSource;
|
||||
|
||||
export interface Options {
|
||||
lang: string | TargetLanguage;
|
||||
|
@ -313,8 +340,11 @@ export class Run {
|
|||
let schemaInputs: Map<string, StringInput> = Map();
|
||||
let schemaSources: List<[uri.URI, SchemaTypeSource]> = List();
|
||||
for (const source of this._options.sources) {
|
||||
if (!isSchemaSource(source)) continue;
|
||||
const { uri, schema } = source;
|
||||
const schemaSource = toSchemaSource(source);
|
||||
|
||||
if (schemaSource === undefined) continue;
|
||||
|
||||
const { uri, schema } = schemaSource;
|
||||
|
||||
let normalizedURI: uri.URI;
|
||||
if (uri === undefined) {
|
||||
|
@ -335,7 +365,7 @@ export class Run {
|
|||
);
|
||||
}
|
||||
|
||||
schemaSources = schemaSources.push([normalizedURI, source]);
|
||||
schemaSources = schemaSources.push([normalizedURI, schemaSource]);
|
||||
}
|
||||
|
||||
if (!schemaSources.isEmpty()) {
|
||||
|
@ -385,7 +415,7 @@ export class Run {
|
|||
this._allInputs.samples[name].description = description;
|
||||
}
|
||||
}
|
||||
} else if (!isSchemaSource(source)) {
|
||||
} else if (!isSchemaSource(source) && !isTypeScriptSource(source)) {
|
||||
assertNever(source);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче