diff --git a/packages/quicktype-core/src/attributes/InferenceFlags.ts b/packages/quicktype-core/src/attributes/InferenceFlags.ts deleted file mode 100644 index cfbb22b5d7..0000000000 --- a/packages/quicktype-core/src/attributes/InferenceFlags.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { TypeAttributeKind } from "./TypeAttributes.js"; - -export type SchemaArrayProvenance = "explicit" | "inferred"; - -class SchemaArrayTypeAttributeKind extends TypeAttributeKind { - public constructor() { - super("schemaArrayProvenance"); - } - - public combine(attrs: SchemaArrayProvenance[]): SchemaArrayProvenance { - return attrs.includes("explicit") ? "explicit" : "inferred"; - } - - public makeInferred(attr: SchemaArrayProvenance): SchemaArrayProvenance { - return attr; - } -} - -export const schemaArrayTypeAttributeKind = new SchemaArrayTypeAttributeKind(); - -// Preserve sample-inference semantics when a top-level array is round-tripped -// through quicktype's JSON Schema output. -export const inferredTopLevelSchemaComment = "qt-inferred-top-level"; diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 71216c0052..38d451ffa2 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -32,10 +32,6 @@ import { import { defaultValueAttributeProducer } from "../attributes/DefaultValue.js"; import { descriptionAttributeProducer } from "../attributes/Description.js"; import { enumValuesAttributeProducer } from "../attributes/EnumValues.js"; -import { - inferredTopLevelSchemaComment, - schemaArrayTypeAttributeKind, -} from "../attributes/InferenceFlags.js"; import { StringTypes } from "../attributes/StringTypes.js"; import { type TypeAttributes, @@ -1113,20 +1109,7 @@ async function addTypesInSchema( } typeBuilder.addAttributes(itemType, singularAttributes); - const provenanceAttributes = - schemaArrayTypeAttributeKind.makeAttributes( - schema.$comment === inferredTopLevelSchemaComment - ? "inferred" - : "explicit", - ); - return typeBuilder.getArrayType( - combineTypeAttributes( - "union", - arrayAttributes, - provenanceAttributes, - ), - itemType, - ); + return typeBuilder.getArrayType(arrayAttributes, itemType); } async function makeObjectType(): Promise { diff --git a/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts b/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts index 250d0ea4b0..227a46da75 100644 --- a/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts +++ b/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts @@ -1,10 +1,6 @@ import { iterableFirst, mapFirst } from "collection-utils"; import { addDescriptionToSchema } from "../../attributes/Description.js"; -import { - inferredTopLevelSchemaComment, - schemaArrayTypeAttributeKind, -} from "../../attributes/InferenceFlags.js"; import { ConvenienceRenderer } from "../../ConvenienceRenderer.js"; import type { Name, Namer } from "../../Naming.js"; import { defined, panic } from "../../support/Support.js"; @@ -182,26 +178,10 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { protected emitSourceStructure(): void { // FIXME: Find a good way to do multiple top-levels. Maybe multiple files? - const topLevel = - this.topLevels.size === 1 - ? defined(mapFirst(this.topLevels)) - : undefined; const topLevelType = - topLevel === undefined ? {} : this.schemaForType(topLevel); - if (topLevel?.kind === "array") { - const provenance = schemaArrayTypeAttributeKind.tryGetInAttributes( - topLevel.getAttributes(), - ); - if ( - provenance === "inferred" || - (provenance === undefined && - topLevel.hasNames && - !topLevel.getNames().areInferred) - ) { - topLevelType.$comment = inferredTopLevelSchemaComment; - } - } - + this.topLevels.size === 1 + ? this.schemaForType(defined(mapFirst(this.topLevels))) + : {}; const schema: Schema = { $schema: "http://json-schema.org/draft-06/schema#", ...topLevelType, diff --git a/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts index f7c91a8f2b..16f3e416b6 100644 --- a/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts +++ b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts @@ -1,6 +1,5 @@ import { arrayIntercalate } from "collection-utils"; -import { schemaArrayTypeAttributeKind } from "../../attributes/InferenceFlags.js"; import { ConvenienceRenderer } from "../../ConvenienceRenderer.js"; import { type Name, type Namer, funPrefixNamer } from "../../Naming.js"; import type { RenderContext } from "../../Renderer.js"; @@ -87,15 +86,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { } protected namedTypeToNameForTopLevel(type: Type): Type | undefined { - // JSON sample arrays collapse to their item type, including when - // round-tripped through quicktype's schema output. Only arrays - // explicitly declared by an input schema retain their wrapper. - if ( - type.kind === "array" && - schemaArrayTypeAttributeKind.tryGetInAttributes( - type.getAttributes(), - ) === "explicit" - ) { + if (type.kind === "array") { return undefined; } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts index 33f37e9ea9..1c282f21a2 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts @@ -1,4 +1,3 @@ -import { schemaArrayTypeAttributeKind } from "../../attributes/InferenceFlags.js"; import { type Name, type Namer, funPrefixNamer } from "../../Naming.js"; import type { RenderContext } from "../../Renderer.js"; import type { OptionValues } from "../../RendererOptions/index.js"; @@ -239,19 +238,14 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { protected emitTypes(): void { this.forEachTopLevel("none", (t, name) => { - const isSchemaArray = - t instanceof ArrayType && - schemaArrayTypeAttributeKind.tryGetInAttributes( - t.getAttributes(), - ) === "explicit"; - if (!t.isPrimitive() && !isSchemaArray) { + if (!t.isPrimitive() && !(t instanceof ArrayType)) { return; } this.ensureBlankLine(); this.emitDescription(this.descriptionForType(t)); this.emitLine( - isSchemaArray ? "export type " : "type ", + t instanceof ArrayType ? "export type " : "type ", name, " = ", this.sourceFor(t).source, diff --git a/test/unit/typescript-top-level-array.test.ts b/test/unit/typescript-top-level-array.test.ts index 4c5d7ced41..7ef7b75c1c 100644 --- a/test/unit/typescript-top-level-array.test.ts +++ b/test/unit/typescript-top-level-array.test.ts @@ -84,20 +84,20 @@ describe("TypeScript top-level arrays", () => { expect(output).toContain("export type SomeInput = string[];"); }); - test("JSON sample arrays still collapse to the element type", async () => { + test("JSON sample arrays emit an alias", async () => { const sample = '[{"label":"a","score":1},{"label":"b","score":2}]'; const output = await typesForJSON("Sample", sample); - expect(output).toContain("export interface Sample"); - expect(output).not.toContain("export type Sample ="); + expect(output).toContain("export type Sample = SampleElement[];"); + expect(output).toContain("export interface SampleElement"); expect(await typesForJSONViaSchema("Sample", sample)).toBe(output); }); - test("JSON primitive arrays still round-trip without an alias", async () => { + test("JSON primitive arrays emit an alias", async () => { const sample = '["one","two"]'; const output = await typesForJSON("Sample", sample); - expect(output).toBe(""); + expect(output).toContain("export type Sample = string[];"); expect(await typesForJSONViaSchema("Sample", sample)).toBe(output); }); });