Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Autorest-canonical Emitter] Update resolveRef for the common type dir #671

Merged
merged 15 commits into from
Apr 19, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: fix
timotheeguerin marked this conversation as resolved.
Show resolved Hide resolved
packages:
- "@azure-tools/typespec-autorest-canonical"
---

Add resolveRef logic for the typespec-autorest-canonical emitter
6 changes: 6 additions & 0 deletions packages/typespec-autorest-canonical/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ Example: Multiple services

Set the newline character for emitting files.

#### `arm-types-dir`

**Type:** `string`

Path to the common-types.json file folder. Default: '${project-root}/../../common-types/resource-management'

#### `omit-unreachable-types`

**Type:** `boolean`
Expand Down
37 changes: 37 additions & 0 deletions packages/typespec-autorest-canonical/src/decorators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Model, ModelProperty, Program, Service, Type } from "@typespec/compiler";
timotheeguerin marked this conversation as resolved.
Show resolved Hide resolved
import { createStateSymbol } from "./lib.js";

export const namespace = "AutorestCanonical";

/**
* Parameters that may be passed to a RefProducer function. Specific RefProducer
* functions may define additional parameters.
*/
export interface RefProducerParams {
service?: Service;
version?: string;
}

/**
* A function that can produce a ref path at the time it is requested.
*/
export type RefProducer = (
program: Program,
entity: Model | ModelProperty,
params: RefProducerParams
) => string | undefined;

const refTargetsKey = createStateSymbol("autorestcanonical.ref");

export function getRef(
program: Program,
entity: Type,
params?: RefProducerParams
): string | undefined {
const refOrProducer = program.stateMap(refTargetsKey).get(entity);
if (typeof refOrProducer === "function") {
return refOrProducer(program, entity, params ?? {});
} else {
return refOrProducer;
}
}
1 change: 1 addition & 0 deletions packages/typespec-autorest-canonical/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./decorators.js";
export { $lib, AutorestCanonicalEmitterOptions } from "./lib.js";
export * from "./openapi.js";
12 changes: 12 additions & 0 deletions packages/typespec-autorest-canonical/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ export interface AutorestCanonicalEmitterOptions {
* @default "never"
*/
"include-x-typespec-name"?: "inline-only" | "never";

/**
* Path to the common-types.json file folder.
* @default "${project-root}/../../common-types/resource-management"
*/
"arm-types-dir"?: string;
}

const EmitterOptionsSchema: JSONSchemaType<AutorestCanonicalEmitterOptions> = {
Expand Down Expand Up @@ -74,6 +80,12 @@ const EmitterOptionsSchema: JSONSchemaType<AutorestCanonicalEmitterOptions> = {
].join("\n"),
},
"azure-resource-provider-folder": { type: "string", nullable: true },
"arm-types-dir": {
type: "string",
nullable: true,
description:
"Path to the common-types.json file folder. Default: '${project-root}/../../common-types/resource-management'",
},
"new-line": {
type: "string",
enum: ["crlf", "lf"],
Expand Down
44 changes: 39 additions & 5 deletions packages/typespec-autorest-canonical/src/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
compilerAssert,
emitFile,
getAllTags,
getDirectoryPath,
getDiscriminator,
getDoc,
getEncode,
Expand All @@ -57,6 +58,8 @@ import {
getProjectedName,
getProperty,
getPropertyType,
getRelativePathFromDirectory,
getRootLength,
getService,
getSummary,
getVisibility,
Expand Down Expand Up @@ -145,6 +148,7 @@ import {
Refable,
} from "./types.js";
import { AutorestCanonicalEmitterContext, resolveOperationId } from "./utils.js";
import { getRef } from "./decorators.js";
timotheeguerin marked this conversation as resolved.
Show resolved Hide resolved

const defaultOptions = {
"output-file": "{azure-resource-provider-folder}/{service-name}/{version}/openapi.json",
Expand All @@ -158,16 +162,18 @@ enum UnsupportedVersioningDecorators {
TypeChangedFrom = "typeChangedFrom",
}

export const namespace = "AutorestCanonical";
export const canonicalVersion = "canonical";

export async function $onEmit(context: EmitContext<AutorestCanonicalEmitterOptions>) {
const resolvedOptions = { ...defaultOptions, ...context.options };
const tcgcSdkContext = createSdkContext(context, "@azure-tools/typespec-autorest-canonical");
const armTypesDir = interpolatePath("{project-root}/../../common-types/resource-management", {
"project-root": context.program.projectRoot,
"emitter-output-dir": context.emitterOutputDir,
});
const armTypesDir = interpolatePath(
resolvedOptions["arm-types-dir"] ?? "{project-root}/../../common-types/resource-management",
{
"project-root": context.program.projectRoot,
"emitter-output-dir": context.emitterOutputDir,
}
);
const options: ResolvedAutorestCanonicalEmitterOptions = {
outputFile: resolvedOptions["output-file"],
outputDir: context.emitterOutputDir,
Expand Down Expand Up @@ -827,7 +833,25 @@ function createOAPIEmitter(
return header;
}

function resolveRef(ref: string) {
const absoluteRef = interpolatePath(ref, {
"arm-types-dir": options.armTypesDir,
});

if (getRootLength(absoluteRef) === 0) {
return absoluteRef; // It is already relative.
}
return getRelativePathFromDirectory(getDirectoryPath(outputFile), absoluteRef, false);
}

function getSchemaOrRef(type: Type, visibility: Visibility): any {
const refUrl = getRef(program, type, { version: context.version, service: context.service });
if (refUrl) {
return {
$ref: resolveRef(refUrl),
};
}

if (type.kind === "Scalar" && program.checker.isStdType(type)) {
return getSchemaForScalar(type);
}
Expand Down Expand Up @@ -915,6 +939,16 @@ function createOAPIEmitter(
}
}

const refUrl = getRef(program, property, {
version: context.version,
service: context.service,
});
if (refUrl) {
return {
$ref: resolveRef(refUrl),
};
}

const parameter = params.get(property);
if (parameter) {
return parameter;
Expand Down
Loading