diff --git a/packages/quicktype-typescript-input/src/index.ts b/packages/quicktype-typescript-input/src/index.ts index f94edb400..38dfdf4d0 100644 --- a/packages/quicktype-typescript-input/src/index.ts +++ b/packages/quicktype-typescript-input/src/index.ts @@ -20,6 +20,7 @@ const settings: PartialArgs = { titles: true, topRef: true, noExtraProps: true, + propOrder: true, }; const compilerOptions: ts.CompilerOptions = { @@ -212,12 +213,20 @@ export function schemaForTypeScriptSources( if ( definition === null || Array.isArray(definition) || - typeof definition !== "object" || - typeof definition.description !== "string" + typeof definition !== "object" ) { continue; } + if (Array.isArray(definition.propertyOrder)) { + (definition as Record).quicktypePropertyOrder = + definition.propertyOrder; + } + + if (typeof definition.description !== "string") { + continue; + } + const description = definition.description as string; const matches = /#TopLevel/.exec(description); if (matches === null) { diff --git a/test/unit/typescript-input.test.ts b/test/unit/typescript-input.test.ts index dedb3335d..ca060f558 100644 --- a/test/unit/typescript-input.test.ts +++ b/test/unit/typescript-input.test.ts @@ -1,6 +1,7 @@ import * as fs from "node:fs"; import * as path from "node:path"; +import { InputData, JSONSchemaInput, quicktype } from "quicktype-core"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; import { afterAll, describe, expect, test } from "vitest"; @@ -18,13 +19,17 @@ afterAll(() => { let uniqueFileIndex = 0; -function schemaForSource(source: string) { +function schemaSourceForSource(source: string) { const fileName = path.join( path.relative(process.cwd(), temporaryDirectory), `input-${uniqueFileIndex++}.ts`, ); fs.writeFileSync(fileName, source); - const result = schemaForTypeScriptSources([fileName]); + return schemaForTypeScriptSources([fileName]); +} + +function schemaForSource(source: string) { + const result = schemaSourceForSource(source); return { name: result.name ?? "", schema: JSON.parse(result.schema), @@ -32,7 +37,33 @@ function schemaForSource(source: string) { }; } +async function swiftForSource(source: string): Promise { + const schemaInput = new JSONSchemaInput(undefined); + await schemaInput.addSource(schemaSourceForSource(source)); + + const inputData = new InputData(); + inputData.addInput(schemaInput); + + const result = await quicktype({ inputData, lang: "swift" }); + return result.lines.join("\n"); +} + describe("schemaForTypeScriptSources", () => { + test("preserves class property declaration order in generated output", async () => { + const output = await swiftForSource(` + class A { + name: string; + age: number; + } + `); + + const nameIndex = output.indexOf("let name: String"); + const ageIndex = output.indexOf("let age: Double"); + expect(nameIndex).toBeGreaterThanOrEqual(0); + expect(ageIndex).toBeGreaterThanOrEqual(0); + expect(nameIndex).toBeLessThan(ageIndex); + }); + test("converts a simple interface", () => { const { schema, uris } = schemaForSource(` export interface Person {