Skip to content

Commit 6368193

Browse files
committed
Add basic tests for multifile splits
1 parent dcf24c5 commit 6368193

File tree

8 files changed

+150
-14
lines changed

8 files changed

+150
-14
lines changed

packages/typespec-autorest/src/openapi.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3148,7 +3148,7 @@ function createFeatureDocumentProxy(
31483148
document: featureItem.document,
31493149
operationExamples: featureExamples,
31503150
outputFile: context.outputFile,
3151-
feature: featureItem.options.featureName,
3151+
feature: featureItem.options.fileName,
31523152
context: context,
31533153
});
31543154
}
@@ -3160,6 +3160,7 @@ function createFeatureDocumentProxy(
31603160
const feature = getFeature(program, type);
31613161
currentFeature = feature.featureName;
31623162
const result: LateBoundReference = new LateBoundReference();
3163+
result.useFeatures = true;
31633164
result.file = feature.fileName!;
31643165
result.getFileContext = () => this.getCurrentFeature();
31653166
return result;
@@ -3176,7 +3177,7 @@ function createFeatureDocumentProxy(
31763177
currentFeature = feature;
31773178
},
31783179
getParameterRef(key: string): string {
3179-
return `common.json/parameters/${encodeURIComponent(key)}`;
3180+
return `./common.json/parameters/${encodeURIComponent(key)}`;
31803181
},
31813182
} as OpenApi2DocumentProxy;
31823183

packages/typespec-autorest/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export class LateBoundReference {
120120
if (!this.isLocal) return this.value;
121121
if (referencingFile === undefined || this.file === undefined || referencingFile === this.file)
122122
return `#/definitions/${this.value}`;
123-
return `${this.file}/definitions/${this.value}`;
123+
return `./${this.file}.json/definitions/${this.value}`;
124124
}
125125
}
126126

packages/typespec-autorest/test/arm/arm.test.ts

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { deepStrictEqual, ok, strictEqual } from "assert";
2-
import { it } from "vitest";
2+
import { expect, it } from "vitest";
33
import { compileOpenAPI, CompileOpenApiWithFeatures } from "../test-host.js";
44

55
it("can share types with a library namespace", async () => {
@@ -585,3 +585,90 @@ it("can split resources and operations by feature", async () => {
585585
"../../common-types/resource-management/v5/privatelinks.json#/definitions/PrivateLinkResourceListResult",
586586
);
587587
});
588+
it("can represent type references within and between features", async () => {
589+
const { featureA, featureB, common } = await CompileOpenApiWithFeatures(
590+
`
591+
592+
@Azure.ResourceManager.Legacy.features(Features)
593+
@armProviderNamespace("Microsoft.Test")
594+
namespace Microsoft.Test;
595+
enum Features {
596+
/** Feature A */
597+
@Azure.ResourceManager.Legacy.featureOptions(#{featureName: "FeatureA", fileName: "featureA", description: "The data for feature A"})
598+
FeatureA: "Feature A",
599+
/** Feature B */
600+
@Azure.ResourceManager.Legacy.featureOptions(#{featureName: "FeatureB", fileName: "featureB", description: "The data for feature B"})
601+
FeatureB: "Feature B",
602+
}
603+
@secret
604+
scalar secretString extends string;
605+
606+
@Azure.ResourceManager.Legacy.feature(Features.FeatureA)
607+
model FooResource is TrackedResource<FooResourceProperties> {
608+
...ResourceNameParameter<FooResource>;
609+
}
610+
611+
@Azure.ResourceManager.Legacy.feature(Features.FeatureA)
612+
model FooResourceProperties {
613+
...DefaultProvisioningStateProperty;
614+
password: secretString;
615+
}
616+
617+
@Azure.ResourceManager.Legacy.feature(Features.FeatureB)
618+
model BarResource is ProxyResource<BarResourceProperties> {
619+
...ResourceNameParameter<BarResource>;
620+
}
621+
@Azure.ResourceManager.Legacy.feature(Features.FeatureB)
622+
model BarResourceProperties {
623+
...DefaultProvisioningStateProperty;
624+
password: secretString;
625+
}
626+
627+
@Azure.ResourceManager.Legacy.feature(Features.FeatureA)
628+
@armResourceOperations
629+
interface Foos extends Azure.ResourceManager.TrackedResourceOperations<FooResource, FooResourceProperties> {}
630+
631+
@Azure.ResourceManager.Legacy.feature(Features.FeatureB)
632+
@armResourceOperations
633+
interface Bars extends Azure.ResourceManager.TrackedResourceOperations<BarResource, BarResourceProperties> {}
634+
`,
635+
["featureA", "featureB", "common"],
636+
{ preset: "azure" },
637+
);
638+
639+
const aFile = featureA as any;
640+
const bFile = featureB as any;
641+
const commonFile = common as any;
642+
643+
expect(aFile.definitions).toBeDefined();
644+
expect(aFile.definitions["FooResource"]).toBeDefined();
645+
expect(aFile.definitions["FooResource"].properties["properties"].$ref).toBe(
646+
"#/definitions/FooResourceProperties",
647+
);
648+
expect(aFile.definitions["FooResourceProperties"]).toBeDefined();
649+
expect(aFile.definitions["FooResourceProperties"].properties["password"].$ref).toBe(
650+
"./common.json/definitions/secretString",
651+
);
652+
expect(aFile.definitions["FooResourceListResult"]).toBeDefined();
653+
expect(aFile.definitions["FooResourceUpdate"]).toBeDefined();
654+
expect(aFile.definitions["FooResourceUpdateProperties"]).toBeDefined();
655+
656+
expect(bFile.definitions).toBeDefined();
657+
expect(bFile.definitions["BarResource"]).toBeDefined();
658+
expect(bFile.definitions["BarResource"].properties["properties"].$ref).toBe(
659+
"#/definitions/BarResourceProperties",
660+
);
661+
expect(bFile.definitions["BarResourceProperties"]).toBeDefined();
662+
expect(bFile.definitions["BarResourceProperties"].properties["password"].$ref).toBe(
663+
"./common.json/definitions/secretString",
664+
);
665+
expect(bFile.definitions["BarResourceProperties"].properties["provisioningState"].$ref).toBe(
666+
"./common.json/definitions/Azure.ResourceManager.ResourceProvisioningState",
667+
);
668+
expect(bFile.definitions["BarResourceListResult"]).toBeDefined();
669+
expect(bFile.definitions["BarResourceUpdate"]).toBeDefined();
670+
expect(bFile.definitions["BarResourceUpdateProperties"]).toBeDefined();
671+
672+
expect(commonFile.definitions).toBeDefined();
673+
expect(commonFile.definitions["secretString"]).toBeDefined();
674+
});

packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Legacy.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export interface ArmFeatureOptions {
2323
readonly featureName: string;
2424
readonly fileName: string;
2525
readonly description: string;
26+
readonly title?: string;
27+
readonly termsOfService?: string;
2628
}
2729

2830
/**

packages/typespec-azure-resource-manager/lib/legacy-types/legacy.decorators.tsp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,14 @@ model ArmFeatureOptions {
6868
/** The associated file name for the features */
6969
fileName: string;
7070

71-
/** The feature description */
71+
/** The feature description in Swagger */
7272
description: string;
73+
74+
/** The feature title in Swagger */
75+
title?: string;
76+
77+
/** The feature terms of service in Swagger */
78+
termsOfService?: string;
7379
}
7480

7581
/**

packages/typespec-azure-resource-manager/src/resource.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1336,10 +1336,26 @@ export function getFeature(program: Program, entity: Type): ArmFeatureOptions {
13361336
const options = getFeatureOptions(program, feature);
13371337
return options;
13381338
}
1339-
case "Interface":
1339+
case "Interface": {
1340+
let feature = getResourceFeature(program, entity);
1341+
if (feature !== undefined) return getFeatureOptions(program, feature);
1342+
const namespace = entity.namespace;
1343+
if (namespace === undefined) return commonFeatureOptions;
1344+
feature = getResourceFeature(program, namespace);
1345+
if (feature === undefined) return commonFeatureOptions;
1346+
return getFeatureOptions(program, feature);
1347+
}
13401348
case "Model": {
13411349
let feature = getResourceFeature(program, entity);
13421350
if (feature !== undefined) return getFeatureOptions(program, feature);
1351+
if (isTemplateInstance(entity)) {
1352+
for (const arg of entity.templateMapper.args) {
1353+
if (arg.entityKind === "Type" && arg.kind === "Model") {
1354+
const options = getFeature(program, arg);
1355+
if (options !== commonFeatureOptions) return options;
1356+
}
1357+
}
1358+
}
13431359
const namespace = entity.namespace;
13441360
if (namespace === undefined) return commonFeatureOptions;
13451361
feature = getResourceFeature(program, namespace);
@@ -1405,10 +1421,15 @@ export const $features: FeaturesDecorator = (
14051421
return featureMap;
14061422
}
14071423
featureMap = new Map<string, ArmFeatureOptions>();
1424+
14081425
for (const member of features.members.values()) {
14091426
const options = getFeatureOptions(program, member); // Ensure defaults are created
14101427
featureMap.set(options.featureName, options);
14111428
}
1429+
const common = [...featureMap.keys()].some((k) => k.toLowerCase() === "common");
1430+
if (!common) {
1431+
featureMap.set("Common", commonFeatureOptions);
1432+
}
14121433
setResourceFeatureSet(program, entity, featureMap);
14131434
return featureMap;
14141435
};

packages/typespec-azure-resource-manager/test/resource.test.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ enum Features {
505505
expect(features).toBeDefined();
506506
ok(features);
507507
const keys = Array.from(features.keys());
508-
expect(keys).toEqual(["FeatureA", "FeatureB"]);
508+
expect(keys).toEqual(["FeatureA", "FeatureB", "Common"]);
509509
expect(features?.get("FeatureA")).toEqual({
510510
featureName: "FeatureA",
511511
fileName: "featureA",
@@ -516,6 +516,11 @@ enum Features {
516516
fileName: "featureB",
517517
description: "",
518518
});
519+
expect(features?.get("Common")).toEqual({
520+
featureName: "Common",
521+
fileName: "common",
522+
description: "",
523+
});
519524

520525
const fooFeature = getResourceFeature(result.program, result.FooResource);
521526
expect(fooFeature?.name).toMatch("FeatureA");
@@ -541,6 +546,10 @@ enum Features {
541546
/** Feature B */
542547
@Azure.ResourceManager.Legacy.featureOptions(#{featureName: "FeatureB", fileName: "feature-b", description: "The data for feature B"})
543548
FeatureB: "Feature B",
549+
550+
/** Common feature */
551+
@Azure.ResourceManager.Legacy.featureOptions(#{featureName: "Common", fileName: "common", description: "The data in common for all features", title: "Common types for FeatureA and FeatureB", termsOfService: "MIT License"})
552+
Common: "Common",
544553
}
545554
@Azure.ResourceManager.Legacy.feature(Features.FeatureA)
546555
model ${t.model("FooResource")} is TrackedResource<FooResourceProperties> {
@@ -563,7 +572,7 @@ enum Features {
563572
expect(features).toBeDefined();
564573
ok(features);
565574
const keys = Array.from(features.keys());
566-
expect(keys).toEqual(["FeatureA", "FeatureB"]);
575+
expect(keys).toEqual(["FeatureA", "FeatureB", "Common"]);
567576
expect(features?.get("FeatureA")).toEqual({
568577
featureName: "FeatureA",
569578
fileName: "feature-a",
@@ -574,6 +583,13 @@ enum Features {
574583
fileName: "feature-b",
575584
description: "The data for feature B",
576585
});
586+
expect(features?.get("Common")).toEqual({
587+
featureName: "Common",
588+
fileName: "common",
589+
description: "The data in common for all features",
590+
title: "Common types for FeatureA and FeatureB",
591+
termsOfService: "MIT License",
592+
});
577593

578594
const fooFeature = getResourceFeature(result.program, result.FooResource);
579595
expect(fooFeature?.name).toMatch("FeatureA");
@@ -652,9 +668,10 @@ enum Features {
652668
expect(features).toBeDefined();
653669
ok(features);
654670
const keys = Array.from(features.keys());
655-
expect(keys).toEqual(["FeatureA", "FeatureB"]);
671+
expect(keys).toEqual(["FeatureA", "FeatureB", "Common"]);
656672
expect(features?.get("FeatureA")).toEqual(featureAObject);
657673
expect(features?.get("FeatureB")).toEqual(featureBObject);
674+
expect(features?.get("Common")).toEqual(defaultObject);
658675

659676
const fooFeature = getFeature(result.program, result.FooResource);
660677
expect(fooFeature).toMatchObject(featureAObject);

website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3416,11 +3416,13 @@ model Azure.ResourceManager.Legacy.ArmFeatureOptions
34163416

34173417
#### Properties
34183418

3419-
| Name | Type | Description |
3420-
| ----------- | -------- | ----------------------------------------- |
3421-
| featureName | `string` | The feature name |
3422-
| fileName | `string` | The associated file name for the features |
3423-
| description | `string` | The feature description |
3419+
| Name | Type | Description |
3420+
| --------------- | -------- | ----------------------------------------- |
3421+
| featureName | `string` | The feature name |
3422+
| fileName | `string` | The associated file name for the features |
3423+
| description | `string` | The feature description in Swagger |
3424+
| title? | `string` | The feature title in Swagger |
3425+
| termsOfService? | `string` | The feature terms of service in Swagger |
34243426

34253427
### `ArmOperationOptions` {#Azure.ResourceManager.Legacy.ArmOperationOptions}
34263428

0 commit comments

Comments
 (0)