Merge pull request #721 from quicktype/typescript-input

TypeScript as a source language
This commit is contained in:
David Siegel 2018-04-01 13:16:27 -05:00 коммит произвёл GitHub
Родитель ee4731951c 68e6f8577d
Коммит ae32fd9486
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 4023 добавлений и 76 удалений

3653
data/lib.d.ts поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -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",
@ -32,6 +32,8 @@
"pluralize": "^7.0.0",
"stream-json": "0.5.2",
"string-to-stream": "^1.1.0",
"typescript": "~2.6.2",
"typescript-json-schema": "^0.21.0",
"unicode-properties": "quicktype/unicode-properties#dist",
"universal-analytics": "^0.4.16",
"urijs": "^1.19.1",
@ -64,7 +66,6 @@
"ts-jest": "^22.4.2",
"ts-node": "^3.3.0",
"tslint": "^5.8.0",
"typescript": "^2.5.3",
"uglify-js": "^3.0.26",
"watch": "^1.0.2"
},

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

8
script/make-encoded-ts-lib.sh Executable file
Просмотреть файл

@ -0,0 +1,8 @@
#!/bin/bash
rm -f /tmp/lib.d.ts /tmp/lib.d.ts.gz
cp ../data/lib.d.ts /tmp/lib.d.ts
gzip -9 /tmp/lib.d.ts
echo -n 'export const encodedDefaultTypeScriptLibrary = "'
base64 /tmp/lib.d.ts.gz | tr -d '\n'
echo '";'

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -470,7 +470,8 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer {
"Serialize",
"Newtonsoft",
"MetadataPropertyHandling",
"DateParseHandling"
"DateParseHandling",
"FromJson"
]);
}

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

@ -168,6 +168,10 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer {
}
export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer {
protected forbiddenNamesForGlobalNamespace(): string[] {
return ["Array", "Date"];
}
protected deserializerFunctionLine(t: Type, name: Name): Sourcelike {
return ["export ", super.deserializerFunctionLine(t, name)];
}

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

@ -1,10 +1,8 @@
"use strict";
import { Base64 } from "js-base64";
import { panic, assert } from "./Support";
import { panic, assert, inflateBase64 } from "./Support";
import { encodedMarkovChain } from "./EncodedMarkovChain";
import * as pako from "pako";
// This must be null, not undefined, because we read it from JSON.
export type SubTrie = number | null | Trie;
@ -90,8 +88,7 @@ export function train(lines: string[], depth: number): MarkovChain {
}
export function load(): MarkovChain {
const bytes = Base64.atob(encodedMarkovChain);
return JSON.parse(pako.inflate(bytes, { to: "string" }));
return JSON.parse(inflateBase64(encodedMarkovChain));
}
export function evaluateFull(mc: MarkovChain, word: string): [number, number[]] {

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

@ -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") {

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

@ -2,6 +2,9 @@
import { Collection, List, Set, isKeyed, isIndexed } from "immutable";
import { Base64 } from "js-base64";
import * as pako from "pako";
export function intercalate<T>(separator: T, items: Collection<any, T>): List<T> {
const acc: T[] = [];
items.forEach((x: T) => {
@ -173,3 +176,8 @@ export async function mapSync<K, V, U>(
}
return coll.map(_v => results[index++]);
}
export function inflateBase64(encoded: string): string {
const bytes = Base64.atob(encoded);
return pako.inflate(bytes, { to: "string" });
}

127
src/TypeScriptInput.ts Normal file
Просмотреть файл

@ -0,0 +1,127 @@
import * as ts from "typescript";
import { PartialArgs, CompilerOptions, generateSchema } from "typescript-json-schema";
import { panic, inflateBase64 } from "./Support";
import { encodedDefaultTypeScriptLibrary } from "./EncodedDefaultTypeScriptLibrary";
const settings: PartialArgs = {
required: true,
titles: true,
topRef: true
};
const compilerOptions: CompilerOptions = {
strictNullChecks: true,
typeRoots: []
};
const libFileName = "lib.d.ts";
let libSource: string | undefined = undefined;
function getLibSource(): string {
if (libSource === undefined) {
libSource = inflateBase64(encodedDefaultTypeScriptLibrary);
}
return libSource;
}
class CompilerHost implements ts.CompilerHost {
constructor(_options: ts.CompilerOptions,
private readonly _sources: {[fileName: string]: string}) {
}
fileExists(fileName: string): boolean {
if (fileName === libFileName) return true;
return Object.prototype.hasOwnProperty.apply(this._sources, fileName);
}
readFile(fileName: string): string | undefined {
if (fileName === libFileName) {
return getLibSource();
}
return this._sources[fileName];
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, _onError?: (message: string) => void, _shouldCreateNewSourceFile?: boolean): ts.SourceFile | undefined {
const sourceText = this.readFile(fileName);
return sourceText !== undefined ? ts.createSourceFile(fileName, sourceText, languageVersion) : undefined;
}
getDefaultLibFileName(_options: CompilerOptions): string {
return libFileName;
}
writeFile(_fileName: string, _data: string, _writeByteOrderMark: boolean, _onError: ((message: string) => void) | undefined, _sourceFiles: ReadonlyArray<ts.SourceFile>): void {
return panic("cannot write file");
}
getCurrentDirectory(): string {
return ".";
}
getDirectories(_path: string): string[] {
return [];
}
getCanonicalFileName(fileName: string): string {
if (this.useCaseSensitiveFileNames()) {
return fileName.toLowerCase();
}
return fileName;
}
useCaseSensitiveFileNames(): boolean {
return false;
}
getNewLine(): string {
return "\n";
}
}
function makeCompilerOptions(jsonCompilerOptions: any, basePath: string = "./"): ts.CompilerOptions {
const compilerOptions = ts.convertCompilerOptionsFromJson(jsonCompilerOptions, basePath).options;
const options: ts.CompilerOptions = {
noEmit: true, emitDecoratorMetadata: true, experimentalDecorators: true, target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
};
for (const k in compilerOptions) {
if (compilerOptions.hasOwnProperty(k)) {
options[k] = compilerOptions[k];
}
}
return options;
}
export function schemaForTypeScriptSources(sourceFileNames: string[]): string;
export function schemaForTypeScriptSources(sources: { [fileName: string]: string }): string;
export function schemaForTypeScriptSources(sources: string[] | { [fileName: string]: string }): string {
const options = makeCompilerOptions(compilerOptions);
let fileNames: string[];
let host: ts.CompilerHost;
if (Array.isArray(sources)) {
/*
const sourceContents: {[fileName: string]: string} = {};
fileNames = [];
for (const fileName of sources) {
const baseName = path.basename(fileName);
sourceContents[baseName] = defined(ts.sys.readFile(fileName));
fileNames.push(baseName);
}
host = new CompilerHost(options, sourceContents);
*/
fileNames = sources;
host = ts.createCompilerHost(options);
} else {
fileNames = Object.getOwnPropertyNames(sources);
host = new CompilerHost(options, sources);
}
const program = ts.createProgram(fileNames, options, host);
const schema = generateSchema(program, "*", settings);
return JSON.stringify(schema);
}

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

@ -11,14 +11,13 @@ import {
getTargetLanguage,
TypeSource,
GraphQLTypeSource,
isJSONSource,
StringInput,
SchemaTypeSource,
isSchemaSource,
quicktypeMultiFile,
SerializedRenderResult,
TargetLanguage,
languageNamed
languageNamed,
TypeScriptTypeSource
} from "..";
import { OptionDefinition } from "../RendererOptions";
@ -33,6 +32,7 @@ import { getStream } from "../get-stream/index";
import { train } from "../MarkovChain";
import { sourcesFromPostmanCollection } from "../PostmanCollection";
import { readableFromFileOrURL, readFromFileOrURL, FetchingJSONSchemaStore } from "./NodeIO";
import { schemaForTypeScriptSources } from "../TypeScriptInput";
import * as telemetry from "./telemetry";
const commandLineArgs = require("command-line-args");
@ -78,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 {
@ -108,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
@ -124,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)
});
}
}
@ -151,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
});
@ -221,6 +240,8 @@ export function inferCLIOptions(opts: Partial<CLIOptions>, defaultLanguage?: str
"If a GraphQL schema is specified, the source language must be GraphQL"
);
srcLang = "graphql";
} else if (opts.src !== undefined && opts.src.length > 0 && opts.src.every(file => _.endsWith(file, ".ts"))) {
srcLang = "typescript";
} else {
assert(srcLang !== "graphql", "Please specify a GraphQL schema with --graphql-schema or --graphql-introspect");
srcLang = withDefault<string>(srcLang, "json");
@ -306,7 +327,7 @@ function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinit
alias: "s",
type: String,
defaultValue: undefined,
typeLabel: "json|schema|graphql|postman",
typeLabel: "json|schema|graphql|postman|typescript",
description: "The source language (default is json)."
},
{
@ -594,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}`);
}
@ -679,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;
@ -687,6 +708,17 @@ export async function makeQuicktypeOptions(
case "schema":
sources = await getSources(options);
break;
case "typescript":
// TODO make this a TypeScriptSource
sources = [
{
kind: "schema",
name: options.topLevel,
schema: schemaForTypeScriptSources(options.src),
topLevelRefs: ["/definitions/"]
}
];
break;
case "postman":
for (const collectionFile of options.src) {
const collectionJSON = fs.readFileSync(collectionFile, "utf8");

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

@ -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);
}
}

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

@ -267,17 +267,16 @@ class JSONFixture extends LanguageFixture {
}
}
// This fixture tests generating Schemas from JSON, then
// making sure that they accept the JSON by generating code from
// the Schema and running the code on the original JSON. Also
// generating a Schema from the Schema and testing that it's
// the same as the original Schema.
class JSONSchemaJSONFixture extends JSONFixture {
// This fixture tests generating code for language X from JSON,
// then generating code for Y from the code for X, making sure
// that the resulting code for Y accepts the JSON by running it
// on the original JSON.
class JSONToXToYFixture extends JSONFixture {
private readonly runLanguage: languages.Language;
constructor(language: languages.Language) {
const schemaLanguage: languages.Language = {
name: "schema",
constructor(private readonly _fixturePrefix: string, languageXName: string, languageXOutputFilename: string, rendererOptions: RendererOptions, skipJSON: string[], language: languages.Language) {
super({
name: languageXName,
base: language.base,
setupCommand: language.setupCommand,
runCommand: (_sample: string) => {
@ -286,31 +285,54 @@ class JSONSchemaJSONFixture extends JSONFixture {
diffViaSchema: false,
skipDiffViaSchema: [],
allowMissingNull: language.allowMissingNull,
output: "schema.json",
topLevel: "schema",
skipJSON: [
"blns-object.json", // AJV refuses to even "compile" the schema we generate
"31189.json", // same here
"ed095.json" // same here on Travis
],
output: languageXOutputFilename,
topLevel: "TopLevel",
skipJSON,
skipMiscJSON: false,
skipSchema: [],
rendererOptions: {},
rendererOptions,
quickTestRendererOptions: [],
sourceFiles: language.sourceFiles
};
super(schemaLanguage);
});
this.runLanguage = language;
this.name = `schema-json-${language.name}`;
this.name = `${this._fixturePrefix}-${language.name}`;
}
runForName(name: string): boolean {
return this.name === name || name === "schema-json";
return this.name === name || name === this._fixturePrefix;
}
async test(filename: string, additionalRendererOptions: RendererOptions, _additionalFiles: string[]) {
// Generate code for Y from X
await quicktypeForLanguage(this.runLanguage, this.language.output, this.language.name, false, additionalRendererOptions);
// Parse the sample with the code generated from its schema, and compare to the sample
compareJsonFileToJson({
expectedFile: filename,
given: { command: this.runLanguage.runCommand(filename) },
strict: false,
allowMissingNull: this.runLanguage.allowMissingNull
});
}
}
// This tests generating Schema from JSON, and then generating
// target code from that Schema. The target code is then run on
// the original JSON. Also generating a Schema from the Schema
// and testing that it's the same as the original Schema.
class JSONSchemaJSONFixture extends JSONToXToYFixture {
constructor(language: languages.Language) {
const skipJSON = [
"blns-object.json", // AJV refuses to even "compile" the schema we generate
"31189.json", // same here
"ed095.json" // same here on Travis
]
super("schema-json", "schema", "schema.json", {}, skipJSON, language);
}
async test(filename: string, additionalRendererOptions: RendererOptions, additionalFiles: string[]) {
let input = JSON.parse(fs.readFileSync(filename, "utf8"));
let schema = JSON.parse(fs.readFileSync("schema.json", "utf8"));
let schema = JSON.parse(fs.readFileSync(this.language.output, "utf8"));
let ajv = new Ajv({ format: "full" });
// Make Ajv's date-time compatible with what we recognize
@ -322,35 +344,97 @@ class JSONSchemaJSONFixture extends JSONFixture {
});
}
// Generate code from the schema
await quicktypeForLanguage(this.runLanguage, "schema.json", "schema", false, additionalRendererOptions);
// Parse the sample with the code generated from its schema, and compare to the sample
compareJsonFileToJson({
expectedFile: filename,
given: { command: this.runLanguage.runCommand(filename) },
strict: false,
allowMissingNull: this.runLanguage.allowMissingNull
});
super.test(filename, additionalRendererOptions, additionalFiles);
// Generate a schema from the schema, making sure the schemas are the same
// FIXME: We could move this to the superclass and test it for all JSON->X->Y
let schemaSchema = "schema-from-schema.json";
await quicktype({
src: ["schema.json"],
srcLang: "schema",
lang: "schema",
topLevel: "schema",
src: [this.language.output],
srcLang: this.language.name,
lang: this.language.name,
topLevel: this.language.topLevel,
out: schemaSchema,
rendererOptions: {}
});
compareJsonFileToJson({
expectedFile: "schema.json",
expectedFile: this.language.output,
given: { file: schemaSchema },
strict: true
});
}
}
// These are all inputs where the top-level type is not directly
// converted to TypeScript, mostly arrays.
const skipTypeScriptTests = [
"no-classes.json",
"optional-union.json",
"pokedex.json", // Enums are screwed up: https://github.com/YousefED/typescript-json-schema/issues/186
"github-events.json",
"00c36.json",
"010b1.json",
"050b0.json",
"06bee.json",
"07c75.json",
"0a91a.json",
"10be4.json",
"13d8d.json",
"176f1.json", // Enum screwed up
"1a7f5.json",
"262f0.json", // Enum screwed up
"2df80.json",
"32d5c.json",
"33d2e.json", // Enum screwed up
"34702.json", // Enum screwed up
"3536b.json",
"3e9a3.json", // duplicate top-level type: https://github.com/quicktype/quicktype/issues/726
"3f1ce.json", // Enum screwed up
"43970.json",
"570ec.json",
"5eae5.json",
"65dec.json", // duplicate top-level type
"66121.json",
"6dec6.json", // Enum screwed up
"6eb00.json",
"77392.json",
"7f568.json",
"7eb30.json", // duplicate top-level type
"7fbfb.json",
"9847b.json",
"996bd.json",
"9a503.json",
"9eed5.json",
"a45b0.json",
"ab0d1.json",
"ad8be.json",
"ae9ca.json", // Enum screwed up
"af2d1.json", // Enum screwed up
"b4865.json",
"c8c7e.json",
"cb0cc.json", // Enum screwed up
"cda6c.json",
"dbfb3.json", // Enum screwed up
"e2a58.json",
"e53b5.json",
"e8a0b.json",
"e8b04.json",
"ed095.json", // top-level is a map
"f3139.json",
"f3edf.json",
"f466a.json"
];
class JSONTypeScriptFixture extends JSONToXToYFixture {
constructor(language: languages.Language) {
super("json-ts", "ts", "typescript.ts", { "just-types": "true" }, [], language);
}
shouldSkipTest(sample: Sample): boolean {
return skipTypeScriptTests.indexOf(path.basename(sample.path)) >= 0;
}
}
// This fixture tests generating code from Schema with features
// that we can't (yet) get from JSON. Right now that's only
// recursive types.
@ -488,6 +572,7 @@ export const allFixtures: Fixture[] = [
new JSONFixture(languages.FlowLanguage),
new JSONFixture(languages.JavaScriptLanguage),
new JSONSchemaJSONFixture(languages.CSharpLanguage),
new JSONTypeScriptFixture(languages.CSharpLanguage),
new JSONSchemaFixture(languages.CSharpLanguage),
new JSONSchemaFixture(languages.JavaLanguage),
new JSONSchemaFixture(languages.GoLanguage),