diff --git a/src/Inputs.ts b/src/Inputs.ts index f3eabff6..84111803 100644 --- a/src/Inputs.ts +++ b/src/Inputs.ts @@ -1,6 +1,6 @@ import * as URI from "urijs"; import * as lodash from "lodash"; -import { Map, List } from "immutable"; +import { Map, List, Set } from "immutable"; import { getStream } from "./get-stream"; import { Readable } from "stream"; @@ -17,7 +17,7 @@ function toReadable(source: string | Readable): Readable { return typeof source === "string" ? stringToStream(source) : source; } -export async function toString(source: string | Readable): Promise { +async function toString(source: string | Readable): Promise { return typeof source === "string" ? source : await getStream(source); } @@ -121,10 +121,6 @@ export class InputData { return Map(this._graphQLs); } - get schemaSources(): List<[uri.URI, SchemaTypeSource]> { - return this._schemaSources; - } - // Returns whether we need IR for this type source private async addOtherTypeSource(source: TypeSource): Promise { if (isGraphQLSource(source)) { @@ -252,4 +248,15 @@ export class InputData { return schemaStore; } + + singleStringSchemaSource(): string | undefined { + if (!this._schemaSources.every(([_, { schema }]) => typeof schema === "string")) { + return undefined; + } + const set = Set(this._schemaSources.map(([_, { schema }]) => schema as string)); + if (set.size === 1) { + return defined(set.first()); + } + return undefined; + } } diff --git a/src/TypeNames.ts b/src/TypeNames.ts index 6ec0c5ae..7a68102e 100644 --- a/src/TypeNames.ts +++ b/src/TypeNames.ts @@ -5,6 +5,7 @@ import * as pluralize from "pluralize"; import { panic, defined } from "./Support"; import { TypeAttributeKind, TypeAttributes } from "./TypeAttributes"; +import { splitIntoWords } from "./Strings"; export type NameOrNames = string | TypeNames; @@ -13,16 +14,29 @@ export type NameOrNames = string | TypeNames; // the names "aaa" and "aaaa" we have the common prefix "aaa" and the // common suffix "aaa", so we will produce the combined name "aaaaaa". function combineNames(names: Collection): string { - const first = names.first(); - if (first === undefined) { + let originalFirst = names.first(); + if (originalFirst === undefined) { return panic("Named type has no names"); } if (names.count() === 1) { + return originalFirst; + } + + const namesSet = names + .map(s => + splitIntoWords(s) + .map(w => w.word.toLowerCase()) + .join("_") + ) + .toSet(); + const first = defined(namesSet.first()); + if (namesSet.size === 1) { return first; } + let prefixLength = first.length; let suffixLength = first.length; - names.rest().forEach(n => { + namesSet.rest().forEach(n => { prefixLength = Math.min(prefixLength, n.length); for (let i = 0; i < prefixLength; i++) { if (first[i] !== n[i]) { diff --git a/src/index.ts b/src/index.ts index 95770b8c..942d4d4f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,7 @@ import { flattenUnions } from "./FlattenUnions"; import { resolveIntersections } from "./ResolveIntersections"; import { replaceObjectType } from "./ReplaceObjectType"; import { ErrorMessage, messageError } from "./Messages"; -import { TypeSource, InputData, toString } from "./Inputs"; +import { TypeSource, InputData } from "./Inputs"; // Re-export essential types and functions export { TargetLanguage } from "./TargetLanguage"; @@ -94,7 +94,11 @@ export class Run { this._options = _.mergeWith(_.clone(options), defaultOptions, (o, s) => (o === undefined ? s : o)); } - private async makeGraph(allInputs: InputData, compressedJSON: CompressedJSON, schemaStore: JSONSchemaStore | undefined): Promise { + private async makeGraph( + allInputs: InputData, + compressedJSON: CompressedJSON, + schemaStore: JSONSchemaStore | undefined + ): Promise { const targetLanguage = getTargetLanguage(this._options.lang); const stringTypeMapping = targetLanguage.stringTypeMapping; const conflateNumbers = !targetLanguage.supportsUnionsWithBothNumberTypes; @@ -231,14 +235,13 @@ export class Run { const compressedJSON = new CompressedJSON(makeDate, makeTime, makeDateTime); const allInputs = new InputData(compressedJSON, this._options.schemaStore); - + if (await allInputs.addTypeSources(this._options.sources)) { needIR = true; } - if (!needIR && allInputs.schemaSources.size === 1) { - const source = defined(allInputs.schemaSources.first()); - const schemaString = await toString(defined(source[1].schema)); + const schemaString = needIR ? undefined : allInputs.singleStringSchemaSource(); + if (schemaString !== undefined) { const lines = JSON.stringify(JSON.parse(schemaString), undefined, 4).split("\n"); lines.push(""); const srr = { lines, annotations: List() }; diff --git a/test/languages.ts b/test/languages.ts index df9c17a4..fe83d776 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -40,7 +40,8 @@ export const CSharpLanguage: Language = { "7fbfb.json", "cda6c.json", "c8c7e.json", - "e53b5.json" + "e53b5.json", + "f82d9.json" ], allowMissingNull: false, output: "QuickType.cs", @@ -359,7 +360,8 @@ export const SwiftLanguage: Language = { "c8c7e.json", "e53b5.json", "e8b04.json", - "fcca3.json" + "fcca3.json", + "f82d9.json" ], allowMissingNull: true, output: "quicktype.swift",