From d437979c8b88870d827e708b580c2fa58d629fc9 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 20 Jul 2026 18:02:24 -0400 Subject: [PATCH] fix(cli): respect --src-lang schema for directory sources (#1278) Co-Authored-By: gpt-5.6-sol via pi --- src/index.ts | 29 +++-- test/unit/directory-source-language.test.ts | 113 ++++++++++++++++++++ 2 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 test/unit/directory-source-language.test.ts diff --git a/src/index.ts b/src/index.ts index 6ae510e25b..3331df0190 100644 --- a/src/index.ts +++ b/src/index.ts @@ -127,6 +127,7 @@ function typeNameFromFilename(filename: string): string { async function samplesFromDirectory( dataDir: string, httpHeaders?: string[], + sourceLanguage?: string, ): Promise { async function readFilesOrURLsInDirectory( d: string, @@ -152,13 +153,21 @@ async function samplesFromDirectory( } if (file.endsWith(".url") || file.endsWith(".json")) { - sourcesInDir.push({ - kind: "json", - name, - samples: [ - await readableFromFileOrURL(fileOrUrl, httpHeaders), - ], - }); + if (sourceLanguage === "schema") { + sourcesInDir.push({ + kind: "schema", + name, + uris: [fileOrUrl], + }); + } else { + sourcesInDir.push({ + kind: "json", + name, + samples: [ + await readableFromFileOrURL(fileOrUrl, httpHeaders), + ], + }); + } } else if (file.endsWith(".schema")) { sourcesInDir.push({ kind: "schema", @@ -876,7 +885,11 @@ async function getSources(options: CLIOptions): Promise { for (const dataDir of directories) { sources = sources.concat( - await samplesFromDirectory(dataDir, options.httpHeader), + await samplesFromDirectory( + dataDir, + options.httpHeader, + options.srcLang, + ), ); } diff --git a/test/unit/directory-source-language.test.ts b/test/unit/directory-source-language.test.ts new file mode 100644 index 0000000000..788efbe9d5 --- /dev/null +++ b/test/unit/directory-source-language.test.ts @@ -0,0 +1,113 @@ +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; + +import { afterEach, describe, expect, test } from "vitest"; + +import { main } from "../../src"; + +const temporaryDirectories: string[] = []; + +const personSchema = JSON.stringify({ + $schema: "http://json-schema.org/draft-07/schema#", + $id: "person.schema.json", + title: "Person", + type: "object", + properties: { + name: { type: "string" }, + age: { + description: "Age in years", + type: "integer", + minimum: 0, + }, + }, + required: ["name"], +}); + +function makeTemporaryDirectory(): string { + const directory = fs.mkdtempSync( + path.join(os.tmpdir(), "quicktype-directory-source-language-"), + ); + temporaryDirectories.push(directory); + return directory; +} + +afterEach(() => { + for (const directory of temporaryDirectories.splice(0)) { + fs.rmSync(directory, { recursive: true, force: true }); + } +}); + +describe("directory source language", () => { + test("explicit schema source language applies to .schema.json files", async () => { + const temporaryDirectory = makeTemporaryDirectory(); + const schemaDirectory = path.join(temporaryDirectory, "schemas"); + const schemaPath = path.join(schemaDirectory, "person.schema.json"); + const directOutputPath = path.join( + temporaryDirectory, + "direct", + "output.ts", + ); + const directoryOutputPath = path.join( + temporaryDirectory, + "directory", + "output.ts", + ); + + fs.mkdirSync(schemaDirectory); + fs.mkdirSync(path.dirname(directOutputPath)); + fs.mkdirSync(path.dirname(directoryOutputPath)); + fs.writeFileSync(schemaPath, personSchema); + + await main([ + "--src-lang", + "schema", + "--lang", + "typescript", + "--out", + directOutputPath, + "--top-level", + "PersonSchema", + schemaPath, + ]); + await main([ + "--src-lang", + "schema", + "--lang", + "typescript", + "--out", + directoryOutputPath, + "--top-level", + "PersonSchema", + schemaDirectory, + ]); + + expect(fs.readFileSync(directoryOutputPath, "utf8")).toBe( + fs.readFileSync(directOutputPath, "utf8"), + ); + }); + + test("default directory detection still recognizes .schema files", async () => { + const temporaryDirectory = makeTemporaryDirectory(); + const schemaDirectory = path.join(temporaryDirectory, "schemas"); + const schemaPath = path.join(schemaDirectory, "person.schema"); + const outputPath = path.join(temporaryDirectory, "output.ts"); + + fs.mkdirSync(schemaDirectory); + fs.writeFileSync(schemaPath, personSchema); + + await main([ + "--lang", + "typescript", + "--out", + outputPath, + "--top-level", + "PersonSchema", + schemaDirectory, + ]); + + const output = fs.readFileSync(outputPath, "utf8"); + expect(output).toContain("age?: number;"); + expect(output).not.toContain("$schema:"); + }); +});