diff --git a/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts index f03e41f27f..0adcaefd30 100644 --- a/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts +++ b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts @@ -493,15 +493,27 @@ function r(name${stringAnnotation}) { protected emitTypes(): void {} - protected emitUsageImportComment(): void { - this.emitLine('// const Convert = require("./file");'); + protected usageModuleName(givenOutputFilename: string): string { + return givenOutputFilename === "stdout" + ? "file" + : givenOutputFilename + .replace(/^.*[/\\]/, "") + .replace(/\.[^.]+$/, ""); + } + + protected emitUsageImportComment(givenOutputFilename: string): void { + this.emitLine( + '// const Convert = require("./', + this.usageModuleName(givenOutputFilename), + '");', + ); } - protected emitUsageComments(): void { + protected emitUsageComments(givenOutputFilename: string): void { this.emitMultiline(`// To parse this data: //`); - this.emitUsageImportComment(); + this.emitUsageImportComment(givenOutputFilename); this.emitLine("//"); this.forEachTopLevel("none", (_t, name) => { const camelCaseName = modifySource(camelCase, name); @@ -537,11 +549,11 @@ function r(name${stringAnnotation}) { }); } - protected emitSourceStructure(): void { + protected emitSourceStructure(givenOutputFilename: string): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { - this.emitUsageComments(); + this.emitUsageComments(givenOutputFilename); } this.emitTypes(); diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts index 76446d9b34..a0a3bfaee2 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts @@ -39,9 +39,9 @@ export class FlowRenderer extends TypeScriptFlowBaseRenderer { }); } - protected emitSourceStructure(): void { + protected emitSourceStructure(givenOutputFilename: string): void { this.emitLine("// @flow"); this.ensureBlankLine(); - super.emitSourceStructure(); + super.emitSourceStructure(givenOutputFilename); } } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts index d4c2393d38..d20f56c19c 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts @@ -191,9 +191,9 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { ); } - protected emitUsageComments(): void { + protected emitUsageComments(givenOutputFilename: string): void { if (this._tsFlowOptions.justTypes) return; - super.emitUsageComments(); + super.emitUsageComments(givenOutputFilename); } protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts index 43537b1464..376036727d 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts @@ -50,7 +50,7 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { protected emitModuleExports(): void {} - protected emitUsageImportComment(): void { + protected emitUsageImportComment(givenOutputFilename: string): void { const topLevelNames: Sourcelike[] = []; this.forEachTopLevel( "none", @@ -62,7 +62,9 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { this.emitLine( "// import { Convert", topLevelNames, - ' } from "./file";', + ' } from "./', + this.usageModuleName(givenOutputFilename), + '";', ); } diff --git a/test/unit/typescript-output-filename.test.ts b/test/unit/typescript-output-filename.test.ts new file mode 100644 index 0000000000..dfa789ea51 --- /dev/null +++ b/test/unit/typescript-output-filename.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, test } from "vitest"; + +import { + InputData, + jsonInputForTargetLanguage, + quicktype, +} from "../../packages/quicktype-core/src/index.js"; + +async function generate( + lang: string, + outputFilename?: string, +): Promise { + const jsonInput = jsonInputForTargetLanguage(lang); + await jsonInput.addSource({ + name: "ExperimentCounts", + samples: ['{"experiments": 3}'], + }); + + const inputData = new InputData(); + inputData.addInput(jsonInput); + const result = await quicktype({ + inputData, + lang, + outputFilename, + }); + return result.lines.join("\n"); +} + +describe("output filename in usage comments", () => { + test("uses output filename in TypeScript usage imports", async () => { + const output = await generate( + "typescript", + "src/cli/ExperimentCounts.ts", + ); + + expect(output).toContain( + '// import { Convert, ExperimentCounts } from "./ExperimentCounts";', + ); + expect(output).not.toContain('from "./file"'); + }); + + test("uses output filename in JavaScript usage require", async () => { + const output = await generate( + "javascript", + "src/cli/ExperimentCounts.js", + ); + + expect(output).toContain( + '// const Convert = require("./ExperimentCounts");', + ); + expect(output).not.toContain('require("./file")'); + }); + + test("uses output filename in Flow usage require", async () => { + const output = await generate("flow", "ExperimentCounts.js"); + + expect(output).toContain( + '// const Convert = require("./ExperimentCounts");', + ); + expect(output).not.toContain('require("./file")'); + }); + + test('falls back to "file" when writing to stdout', async () => { + const tsOutput = await generate("typescript"); + expect(tsOutput).toContain(' } from "./file";'); + + const jsOutput = await generate("javascript"); + expect(jsOutput).toContain('// const Convert = require("./file");'); + }); +});