Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion packages/quicktype-core/src/rewrites/CombineClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,15 @@ function tryAddToClique(
c: ClassType,
clique: Clique,
onlyWithSameProperties: boolean,
topLevels: ReadonlySet<Type>,
): boolean {
if (
topLevels.has(c) &&
clique.members.some((member) => topLevels.has(member))
) {
return false;
}

for (const prototype of clique.prototypes) {
if (prototype.structurallyCompatible(c)) {
clique.members.push(c);
Expand All @@ -132,6 +140,10 @@ function findSimilarityCliques(
onlyWithSameProperties: boolean,
includeFixedClasses: boolean,
): ClassType[][] {
// Distinct named top-levels must not be heuristically combined. Exactly
// identical top-levels can already have been deduplicated during inference.
// Top-levels can still combine with nested classes to preserve recursion.
const topLevels = new Set(graph.topLevels.values());
const classCandidates = Array.from(
graph.allNamedTypesSeparated().objects,
).filter(
Expand All @@ -142,7 +154,9 @@ function findSimilarityCliques(
for (const c of classCandidates) {
let cliqueIndex: number | undefined;
for (let i = 0; i < cliques.length; i++) {
if (tryAddToClique(c, cliques[i], onlyWithSameProperties)) {
if (
tryAddToClique(c, cliques[i], onlyWithSameProperties, topLevels)
) {
cliqueIndex = i;
break;
}
Expand Down
84 changes: 84 additions & 0 deletions test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,89 @@ abstract class LanguageFixture extends Fixture {
}
}

class MultipleJSONTopLevelsFixture extends LanguageFixture {
readonly name = "csharp-multiple-json-top-levels";
private readonly fixtureDirectory = "test/inputs/json/priority/issue-1630";

constructor() {
super({
...languages.CSharpLanguageSystemTextJson,
base: "test/fixtures/csharp-multiple-json-top-levels",
});
}

runForName(name: string): boolean {
return (
name === this.name ||
name === "csharp-SystemTextJson" ||
name === "json"
);
}

getSamples(sources: string[]): { priority: Sample[]; others: Sample[] } {
if (sources.length > 0) return { priority: [], others: [] };

return {
priority: [
{
path: this.fixtureDirectory,
additionalRendererOptions: {},
saveOutput: true,
},
],
others: [],
};
}

shouldSkipTest(_sample: Sample): boolean {
return false;
}

async runQuicktype(
directory: string,
additionalRendererOptions: RendererOptions,
): Promise<void> {
await quicktype({
srcLang: "json",
lang: this.language.name,
src: [directory],
out: this.language.output,
alphabetizeProperties: true,
rendererOptions: _.merge(
{},
this.language.rendererOptions,
additionalRendererOptions,
),
quiet: true,
telemetry: "disable",
debug: "provenance",
});
}

async test(
directory: string,
additionalRendererOptions: RendererOptions,
_additionalFiles: string[],
): Promise<number> {
if (this.language.compileCommand) {
await execAsync(this.language.compileCommand);
}

const samples = testsInDir(directory, "json");
for (const sample of samples) {
compareJsonFileToJson(
comparisonArgs(
this.language,
sample,
sample,
additionalRendererOptions,
),
);
}
return samples.length;
}
}

class JSONFixture extends LanguageFixture {
constructor(
language: languages.Language,
Expand Down Expand Up @@ -1742,6 +1825,7 @@ export const allFixtures: Fixture[] = [
languages.CSharpLanguageSystemTextJson,
"csharp-SystemTextJson",
),
new MultipleJSONTopLevelsFixture(),
new JSONFixture(languages.JavaLanguage),
new JSONFixture(
languages.JavaLanguageWithLegacyDateTime,
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/csharp-multiple-json-top-levels/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin
obj
43 changes: 43 additions & 0 deletions test/fixtures/csharp-multiple-json-top-levels/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.IO;

namespace QuickType
{
class Program
{
static void Main(string[] args)
{
var path = args[0];
var json = File.ReadAllText(path);
string output;

switch (Path.GetFileName(path))
{
case "AccountsGet.Request.json":
{
AccountsGetRequest value = AccountsGetRequest.FromJson(json);
output = value.ToJson();
break;
}
case "AuthGet.Request.json":
{
AuthGetRequest value = AuthGetRequest.FromJson(json);
AuthGetRequestOptions options = value.Options;
output = value.ToJson();
break;
}
case "TransactionsGet.Request.json":
{
TransactionsGetRequest value = TransactionsGetRequest.FromJson(json);
TransactionsGetRequestOptions options = value.Options;
output = value.ToJson();
break;
}
default:
throw new ArgumentException($"Unexpected fixture input: {path}");
}

Console.WriteLine(output);
}
}
}
9 changes: 9 additions & 0 deletions test/fixtures/csharp-multiple-json-top-levels/test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>
</Project>
5 changes: 5 additions & 0 deletions test/inputs/json/priority/issue-1630/AccountsGet.Request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"client_id": "1234abcd5678efgh90ij",
"secret": "1234abcd5678efgh90ij",
"access_token": "1234abcd5678efgh90ij"
}
8 changes: 8 additions & 0 deletions test/inputs/json/priority/issue-1630/AuthGet.Request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"client_id": "1234abcd5678efgh90ij",
"secret": "1234abcd5678efgh90ij",
"access_token": "1234abcd5678efgh90ij",
"options": {
"account_ids": ["abc", "def", "ghi"]
}
}
12 changes: 12 additions & 0 deletions test/inputs/json/priority/issue-1630/TransactionsGet.Request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"client_id": "1234abcd5678efgh90ij",
"secret": "1234abcd5678efgh90ij",
"access_token": "1234abcd5678efgh90ij",
"start_date": "2020-01-01",
"end_date": "2020-01-31",
"options": {
"account_ids": ["abc", "def", "ghi"],
"count": 100,
"offset": 0
}
}
Loading