diff --git a/packages/quicktype-core/src/language/Golang/GolangRenderer.ts b/packages/quicktype-core/src/language/Golang/GolangRenderer.ts index 72d50068e8..37cbfaf5e4 100644 --- a/packages/quicktype-core/src/language/Golang/GolangRenderer.ts +++ b/packages/quicktype-core/src/language/Golang/GolangRenderer.ts @@ -12,7 +12,7 @@ import { assert, defined } from "../../support/Support.js"; import type { TargetLanguage } from "../../TargetLanguage.js"; import { type ClassProperty, - type ClassType, + ClassType, type EnumType, type Type, type TypeKind, @@ -194,28 +194,37 @@ export class GoRenderer extends ConvenienceRenderer { if ( this._options.multiFileOutput && this._options.justTypes === false && - this._options.justTypesAndPackage === false && - this.leadingComments === undefined + this._options.justTypesAndPackage === false ) { - this.emitLineOnce( - "// Code generated from JSON Schema using quicktype. DO NOT EDIT.", - ); - this.emitLineOnce( - "// To parse and unparse this JSON data, add this code to your project and do:", - ); - this.emitLineOnce("//"); - const ref = modifySource(camelCase, name); - this.emitLineOnce( - "// ", - ref, - ", err := ", - defined(this._topLevelUnmarshalNames.get(name)), - "(bytes)", - ); - this.emitLineOnce("// bytes, err = ", ref, ".Marshal()"); + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } else { + this.emitLineOnce( + "// Code generated from JSON Schema using quicktype. DO NOT EDIT.", + ); + this.emitLineOnce( + "// To parse and unparse this JSON data, add this code to your project and do:", + ); + this.emitLineOnce("//"); + const ref = modifySource(camelCase, name); + this.emitLineOnce( + "// ", + ref, + ", err := ", + defined(this._topLevelUnmarshalNames.get(name)), + "(bytes)", + ); + this.emitLineOnce("// bytes, err = ", ref, ".Marshal()"); + } } - this.emitPackageDefinitons(true); + const imports = + t instanceof ClassType + ? this.collectClassImports(t) + : t instanceof UnionType + ? this.collectUnionImports(t) + : undefined; + this.emitPackageDefinitons(true, imports); const unmarshalName = defined(this._topLevelUnmarshalNames.get(name)); if (this.namedTypeToNameForTopLevel(t) === undefined) { @@ -305,7 +314,7 @@ export class GoRenderer extends ConvenienceRenderer { private emitUnion(u: UnionType, unionName: Name): void { this.startFile(unionName); - this.emitPackageDefinitons(false); + this.emitPackageDefinitons(false, this.collectUnionImports(u)); const [hasNull, nonNulls] = removeNullFromUnion(u); const isNullableArg = hasNull !== null ? "true" : "false"; @@ -610,10 +619,13 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, if ( this._options.multiFileOutput === false && this._options.justTypes === false && - this._options.justTypesAndPackage === false && - this.leadingComments === undefined + this._options.justTypesAndPackage === false ) { - this.emitSingleFileHeaderComments(); + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } else { + this.emitSingleFileHeaderComments(); + } this.emitPackageDefinitons(false, this.collectAllImports()); } diff --git a/test/fixtures.ts b/test/fixtures.ts index dece181ef6..a38a52d77f 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -25,7 +25,16 @@ import { callAndExpectFailure, } from "./utils"; import * as languages from "./languages"; -import type { LanguageName, Option, RendererOptions } from "quicktype-core"; +import { + FetchingJSONSchemaStore, + InputData, + JSONSchemaInput, + type LanguageName, + type Option, + type RendererOptions, + quicktype as quicktypeCore, + quicktypeMultiFile, +} from "quicktype-core"; import { mustNotHappen, defined, @@ -823,6 +832,83 @@ class JSONSchemaFixture extends LanguageFixture { } } +// `leadingComments` is a quicktype-core API option, so the CLI fixture path +// cannot exercise it. +class LeadingCommentsGoFixture extends JSONSchemaFixture { + constructor() { + super(languages.GoLanguage, "schema-golang-leading-comments"); + } + + getSamples(sources: string[]): { priority: Sample[]; others: Sample[] } { + return samplesFromSources( + sources, + ["test/inputs/schema/date-time.schema"], + [], + "schema", + ); + } + + private async inputData(filename: string): Promise { + const schemaInput = new JSONSchemaInput(new FetchingJSONSchemaStore()); + await schemaInput.addSource({ + name: this.language.topLevel, + schema: fs.readFileSync(filename, "utf8"), + }); + const inputData = new InputData(); + inputData.addInput(schemaInput); + return inputData; + } + + async runQuicktype( + filename: string, + additionalRendererOptions: RendererOptions, + ): Promise { + const rendererOptions = _.merge( + {}, + this.language.rendererOptions, + additionalRendererOptions, + ); + const result = await quicktypeCore({ + inputData: await this.inputData(filename), + lang: this.language.name, + leadingComments: [], + rendererOptions, + }); + fs.writeFileSync(this.language.output, result.lines.join("\n")); + + const multiFileResult = await quicktypeMultiFile({ + inputData: await this.inputData(filename), + lang: this.language.name, + leadingComments: [], + rendererOptions: { + ...rendererOptions, + "multi-file-output": true, + }, + }); + mkdirs("multi"); + for (const [outputFilename, output] of multiFileResult) { + fs.writeFileSync( + path.join("multi", outputFilename), + output.lines.join("\n"), + ); + } + } + + async test( + filename: string, + additionalRendererOptions: RendererOptions, + additionalFiles: string[], + ): Promise { + const numFiles = await super.test( + filename, + additionalRendererOptions, + additionalFiles, + ); + await execAsync("go test multi/*.go"); + return numFiles + testsInDir("multi", "go").length; + } +} + type TreeSitterTarget = { displayName: string; language: languages.Language; @@ -1602,6 +1688,7 @@ export const allFixtures: Fixture[] = [ "schema-java-lombok", ), new JSONSchemaFixture(languages.GoLanguage), + new LeadingCommentsGoFixture(), new JSONSchemaFixture(languages.CJSONLanguage), new JSONSchemaFixture(languages.CPlusPlusLanguage), new JSONSchemaFixture(languages.RustLanguage),