Skip to content

Commit

Permalink
Fix emit of bundled schemas when has references and is used multiple …
Browse files Browse the repository at this point in the history
…times (#2147)

The first time such schemas were emitted, `emitSourceFile` polluted its
definition, so all subsequent references would include the pollution.
  • Loading branch information
bterlson authored Jul 5, 2023
1 parent 9f055a1 commit 0080b50
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@typespec/json-schema",
"comment": "Fix a bug that could result in a schema being bundled more than once.",
"type": "none"
}
],
"packageName": "@typespec/json-schema"
}
2 changes: 1 addition & 1 deletion packages/json-schema/src/json-schema-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ export class JsonSchemaEmitter extends TypeEmitter<Record<string, any>, JSONSche
throw new Error("Emit error - multiple decls in single schema per file mode");
}

content = decls[0].value;
content = { ...decls[0].value };

if (sourceFile.meta.bundledRefs.length > 0) {
// bundle any refs, including refs of refs
Expand Down
46 changes: 46 additions & 0 deletions packages/json-schema/test/bundling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,50 @@ describe("bundling", () => {
assert.strictEqual(schemas["test.json"].$defs, undefined);
assert.strictEqual(schemas["Bar.json"].$id, "Bar.json");
});

it("doesn't create duplicate defs for transitive references", async () => {
const schemas = await emitSchema(
`
model A {}
model B {
refA: A;
}
@jsonSchema
model C {
refB: B;
}
@jsonSchema
model D {
refB: B;
}
`,
{},
{ emitNamespace: false, emitTypes: ["C", "D"] }
);

const depSchemas = {
B: {
$schema: "https://json-schema.org/draft/2020-12/schema",
$id: "B.json",
type: "object",
properties: {
refA: {
$ref: "A.json",
},
},
required: ["refA"],
},
A: {
$schema: "https://json-schema.org/draft/2020-12/schema",
$id: "A.json",
type: "object",
properties: {},
},
};
assert.deepStrictEqual(schemas["C.json"].$defs, depSchemas);
assert.deepStrictEqual(schemas["D.json"].$defs, depSchemas);
});
});
11 changes: 9 additions & 2 deletions packages/json-schema/test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function getHostForCadlFile(contents: string, decorators?: Record<s
export async function emitSchema(
code: string,
options: JSONSchemaEmitterOptions = {},
testOptions: { emitNamespace: boolean } = { emitNamespace: true }
testOptions: { emitNamespace?: boolean; emitTypes?: string[] } = { emitNamespace: true }
) {
if (!options["file-type"]) {
options["file-type"] = "json";
Expand All @@ -37,7 +37,14 @@ export async function emitSchema(
emitterOutputDir: "cadl-output",
options,
} as any);
emitter.emitType(host.program.resolveTypeReference("test")[0]!);
if (testOptions.emitTypes === undefined) {
emitter.emitType(host.program.resolveTypeReference("test")[0]!);
} else {
for (const name of testOptions.emitTypes) {
emitter.emitType(host.program.resolveTypeReference(name)[0]!);
}
}

await emitter.writeOutput();
const schemas: Record<string, any> = {};
const files = await emitter.getProgram().host.readDir("./cadl-output");
Expand Down

0 comments on commit 0080b50

Please sign in to comment.