From 8f62101c6378741ef698a06654d79409c79470c8 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 19 Apr 2023 13:34:04 -0700 Subject: [PATCH 1/2] Add sourceModel and sourceOperation --- packages/compiler/core/checker.ts | 6 ++++-- packages/compiler/core/projector.ts | 7 +++++++ packages/compiler/core/types.ts | 10 ++++++++++ packages/compiler/test/checker/model.test.ts | 13 +++++++++++++ packages/compiler/test/checker/operations.test.ts | 12 ++++++++++++ packages/html-program-viewer/src/ui.tsx | 2 ++ 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/compiler/core/checker.ts b/packages/compiler/core/checker.ts index d19681ef982..2128c122736 100644 --- a/packages/compiler/core/checker.ts +++ b/packages/compiler/core/checker.ts @@ -1602,14 +1602,14 @@ export function createChecker(program: Program): Checker { let decorators: DecoratorApplication[] = []; // Is this a definition or reference? - let parameters: Model, returnType: Type; + let parameters: Model, returnType: Type, sourceOperation: Operation | undefined; if (node.signature.kind === SyntaxKind.OperationSignatureReference) { // Attempt to resolve the operation const baseOperation = checkOperationIs(node, node.signature.baseOperation, mapper); if (!baseOperation) { return errorType; } - + sourceOperation = baseOperation; // Reference the same return type and create the parameters type parameters = cloneType(baseOperation.parameters); returnType = baseOperation.returnType; @@ -1629,6 +1629,7 @@ export function createChecker(program: Program): Checker { parameters, returnType, decorators, + sourceOperation, interface: parentInterface, }); @@ -2328,6 +2329,7 @@ export function createChecker(program: Program): Checker { const isBase = checkModelIs(node, node.is, mapper); if (isBase) { + type.sourceModel = isBase; checkDeprecated(isBase, node.is!); // copy decorators decorators.push(...isBase.decorators); diff --git a/packages/compiler/core/projector.ts b/packages/compiler/core/projector.ts index 860dd71f0d2..ee0b9b8ccaa 100644 --- a/packages/compiler/core/projector.ts +++ b/packages/compiler/core/projector.ts @@ -278,6 +278,9 @@ export function createProjector( if (model.baseModel) { projectedModel.baseModel = projectType(model.baseModel) as Model; } + if (model.sourceModel) { + projectedModel.sourceModel = projectType(model.sourceModel) as Model; + } if (model.indexer) { projectedModel.indexer = { @@ -406,6 +409,10 @@ export function createProjector( projectedOp.templateArguments = mutate(projectedOp.templateMapper.args); } + if (op.sourceOperation) { + projectedOp.sourceOperation = projectType(op.sourceOperation) as Operation; + } + if (op.namespace) { projectedOp.namespace = projectedNamespaceScope(); } diff --git a/packages/compiler/core/types.ts b/packages/compiler/core/types.ts index d3786e13050..229ab9a5497 100644 --- a/packages/compiler/core/types.ts +++ b/packages/compiler/core/types.ts @@ -226,6 +226,11 @@ export interface Model extends BaseType, DecoratedType, TemplatedTypeBase { */ derivedModels: Model[]; + /** + * The model that is referenced via `model is`. + */ + sourceModel?: Model; + /** * Late-bound symbol of this model type. * @internal @@ -344,6 +349,11 @@ export interface Operation extends BaseType, DecoratedType, TemplatedTypeBase { interface?: Interface; parameters: Model; returnType: Type; + + /** + * The operation that is referenced via `op is`. + */ + sourceOperation?: Operation; } export interface Namespace extends BaseType, DecoratedType { diff --git a/packages/compiler/test/checker/model.test.ts b/packages/compiler/test/checker/model.test.ts index 252aaac7328..9667adb442d 100644 --- a/packages/compiler/test/checker/model.test.ts +++ b/packages/compiler/test/checker/model.test.ts @@ -563,6 +563,19 @@ describe("compiler: models", () => { }); }); + it("keeps reference to source model", async () => { + testHost.addTypeSpecFile( + "main.tsp", + ` + import "./dec.js"; + @test model A { } + @test model B is A { }; + ` + ); + const { A, B } = (await testHost.compile("main.tsp")) as { A: Model; B: Model }; + strictEqual(B.sourceModel, A); + }); + it("copies decorators", async () => { testHost.addTypeSpecFile( "main.tsp", diff --git a/packages/compiler/test/checker/operations.test.ts b/packages/compiler/test/checker/operations.test.ts index e6223eba963..1d13c7020e3 100644 --- a/packages/compiler/test/checker/operations.test.ts +++ b/packages/compiler/test/checker/operations.test.ts @@ -22,6 +22,18 @@ describe("compiler: operations", () => { strictEqual((foo.returnType as IntrinsicType).name, "void"); }); + it("keeps reference to source operation", async () => { + testHost.addTypeSpecFile( + "main.tsp", + ` + @test op a(): void; + @test op b is a; + ` + ); + const { a, b } = (await testHost.compile("main.tsp")) as { a: Operation; b: Operation }; + strictEqual(b.sourceOperation, a); + }); + it("can be templated and referenced to define other operations", async () => { testHost.addTypeSpecFile( "main.tsp", diff --git a/packages/html-program-viewer/src/ui.tsx b/packages/html-program-viewer/src/ui.tsx index cb3a44ab6b7..7ff490faa5e 100644 --- a/packages/html-program-viewer/src/ui.tsx +++ b/packages/html-program-viewer/src/ui.tsx @@ -225,6 +225,7 @@ const OperationUI: FunctionComponent<{ type: Operation }> = ({ type }) => { interface: "skip", parameters: "nested", returnType: "ref", + sourceOperation: "ref", }} /> ); @@ -247,6 +248,7 @@ const ModelUI: FunctionComponent<{ type: Model }> = ({ type }) => { baseModel: "ref", derivedModels: "ref", properties: "nested", + sourceModel: "ref", }} /> ); From 25c19107e13d2eab3c55be8afb14042602aade9c Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 19 Apr 2023 13:35:23 -0700 Subject: [PATCH 2/2] Changelog --- ...eature-source-model-operation_2023-04-19-20-35.json | 10 ++++++++++ ...eature-source-model-operation_2023-04-19-20-35.json | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 common/changes/@typespec/compiler/feature-source-model-operation_2023-04-19-20-35.json create mode 100644 common/changes/@typespec/html-program-viewer/feature-source-model-operation_2023-04-19-20-35.json diff --git a/common/changes/@typespec/compiler/feature-source-model-operation_2023-04-19-20-35.json b/common/changes/@typespec/compiler/feature-source-model-operation_2023-04-19-20-35.json new file mode 100644 index 00000000000..0d6aa13a08a --- /dev/null +++ b/common/changes/@typespec/compiler/feature-source-model-operation_2023-04-19-20-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/compiler", + "comment": "Api: Added `sourceModel` and `sourceOperation` on `Model` and `Operation` respectively.", + "type": "none" + } + ], + "packageName": "@typespec/compiler" +} \ No newline at end of file diff --git a/common/changes/@typespec/html-program-viewer/feature-source-model-operation_2023-04-19-20-35.json b/common/changes/@typespec/html-program-viewer/feature-source-model-operation_2023-04-19-20-35.json new file mode 100644 index 00000000000..45318248f31 --- /dev/null +++ b/common/changes/@typespec/html-program-viewer/feature-source-model-operation_2023-04-19-20-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/html-program-viewer", + "comment": "Update to show new `sourceModel` and `sourceOperation`", + "type": "none" + } + ], + "packageName": "@typespec/html-program-viewer" +} \ No newline at end of file