http-client-java, access/usage on namespace (#4417)
1. basic logic is that if there is not access/usage decorator on model, check the decorator on its parent 2. a cache is put so that one namespace is only checked once (`undefined` is also included as a result) <-- it is just performance There is a corner case that ```ts @usage(Usage.input) namespace L1 { @usage(Usage.output) namespace L2 { model M {} } } ``` that in some interpretation M may be input+output. But TCGC and the logic in PR both gives output. I guess this be OK. Local test (as TCGC seems not able to handle my case in cadl-ranch, that models is defined in a sub namespace) ``` @supportedBy("dpg") @scenarioService("/client/initialization") @access(Access.public) @usage(Usage.output) namespace Client.AccessTest; // public output model OutputModel { name: string; } // public output model OutputModel2 { name: string; } // internal input+output @access(Access.internal) @usage(Usage.input | Usage.output) model Model3 { name: string; } @access(Access.internal) namespace InternalOperations { // internal op get(): OutputModel; } ```
This commit is contained in:
Родитель
40762bf852
Коммит
72478a51b4
|
@ -368,23 +368,24 @@ export class CodeModelBuilder {
|
|||
private processModels() {
|
||||
const processedSdkModels: Set<SdkModelType | SdkEnumType> = new Set();
|
||||
|
||||
// lambda to mark model as public
|
||||
const modelAsPublic = (model: SdkModelType | SdkEnumType) => {
|
||||
const schema = this.processSchemaFromSdkType(model, "");
|
||||
|
||||
this.trackSchemaUsage(schema, {
|
||||
usage: [SchemaContext.Public],
|
||||
});
|
||||
};
|
||||
// cache resolved value of access/usage for the namespace
|
||||
// the value can be set as undefined
|
||||
// it resolves the value from that namespace and its parent namespaces
|
||||
const accessCache: Map<Namespace, string | undefined> = new Map();
|
||||
const usageCache: Map<Namespace, SchemaContext[] | undefined> = new Map();
|
||||
|
||||
const sdkModels: (SdkModelType | SdkEnumType)[] = getAllModels(this.sdkContext);
|
||||
|
||||
// process sdk models
|
||||
for (const model of sdkModels) {
|
||||
if (!processedSdkModels.has(model)) {
|
||||
const access = getAccess(model.__raw);
|
||||
const access = getAccess(model.__raw, accessCache);
|
||||
if (access === "public") {
|
||||
modelAsPublic(model);
|
||||
const schema = this.processSchemaFromSdkType(model, "");
|
||||
|
||||
this.trackSchemaUsage(schema, {
|
||||
usage: [SchemaContext.Public],
|
||||
});
|
||||
} else if (access === "internal") {
|
||||
const schema = this.processSchemaFromSdkType(model, model.name);
|
||||
|
||||
|
@ -393,7 +394,7 @@ export class CodeModelBuilder {
|
|||
});
|
||||
}
|
||||
|
||||
const usage = getUsage(model.__raw);
|
||||
const usage = getUsage(model.__raw, usageCache);
|
||||
if (usage) {
|
||||
const schema = this.processSchemaFromSdkType(model, "");
|
||||
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
import { ApiVersions, Parameter } from "@autorest/codemodel";
|
||||
import { getOperationLink } from "@azure-tools/typespec-azure-core";
|
||||
import {
|
||||
SdkClient,
|
||||
SdkContext,
|
||||
listOperationGroups,
|
||||
listOperationsInOperationGroup,
|
||||
} from "@azure-tools/typespec-client-generator-core";
|
||||
import { Operation } from "@typespec/compiler";
|
||||
import { Version } from "@typespec/versioning";
|
||||
import { getAccess } from "./type-utils.js";
|
||||
|
||||
export class ClientContext {
|
||||
baseUri: string;
|
||||
|
@ -58,31 +50,4 @@ export class ClientContext {
|
|||
}
|
||||
return addedVersions;
|
||||
}
|
||||
|
||||
preProcessOperations(sdkContext: SdkContext, client: SdkClient) {
|
||||
const operationGroups = listOperationGroups(sdkContext, client);
|
||||
const operations = listOperationsInOperationGroup(sdkContext, client);
|
||||
for (const operation of operations) {
|
||||
const opLink = getOperationLink(sdkContext.program, operation, "polling");
|
||||
if (opLink && opLink.linkedOperation) {
|
||||
const access = getAccess(opLink.linkedOperation);
|
||||
if (access !== "public") {
|
||||
this.ignoredOperations.add(opLink.linkedOperation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const operationGroup of operationGroups) {
|
||||
const operations = listOperationsInOperationGroup(sdkContext, operationGroup);
|
||||
for (const operation of operations) {
|
||||
const opLink = getOperationLink(sdkContext.program, operation, "polling");
|
||||
if (opLink && opLink.linkedOperation) {
|
||||
const access = getAccess(opLink.linkedOperation);
|
||||
if (access !== "public") {
|
||||
this.ignoredOperations.add(opLink.linkedOperation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { SchemaContext } from "@autorest/codemodel";
|
||||
import { getUnionAsEnum } from "@azure-tools/typespec-azure-core";
|
||||
import {
|
||||
SdkDurationType,
|
||||
|
@ -12,6 +11,7 @@ import {
|
|||
EnumMember,
|
||||
IntrinsicScalarName,
|
||||
Model,
|
||||
Namespace,
|
||||
Program,
|
||||
Scalar,
|
||||
StringLiteral,
|
||||
|
@ -27,6 +27,7 @@ import {
|
|||
isTypeSpecValueTypeOf,
|
||||
} from "@typespec/compiler";
|
||||
import { DurationSchema } from "./common/schemas/time.js";
|
||||
import { SchemaContext } from "./common/schemas/usage.js";
|
||||
import { getNamespace } from "./utils.js";
|
||||
|
||||
/** Acts as a cache for processing inputs.
|
||||
|
@ -227,15 +228,19 @@ export function modelIs(model: Model, name: string, namespace: string): boolean
|
|||
return false;
|
||||
}
|
||||
|
||||
export function getAccess(type: Type | undefined): string | undefined {
|
||||
export function getAccess(
|
||||
type: Type | undefined,
|
||||
accessCache: Map<Namespace, string | undefined>
|
||||
): string | undefined {
|
||||
if (
|
||||
type &&
|
||||
(type.kind === "Model" ||
|
||||
type.kind === "Operation" ||
|
||||
type.kind === "Enum" ||
|
||||
type.kind === "Union")
|
||||
type.kind === "Union" ||
|
||||
type.kind === "Namespace")
|
||||
) {
|
||||
return getDecoratorScopedValue(type, "$access", (it) => {
|
||||
let access = getDecoratorScopedValue(type, "$access", (it) => {
|
||||
const value = it.args[0].value;
|
||||
if ("kind" in value && value.kind === "EnumMember") {
|
||||
return value.name;
|
||||
|
@ -243,6 +248,16 @@ export function getAccess(type: Type | undefined): string | undefined {
|
|||
return undefined;
|
||||
}
|
||||
});
|
||||
if (!access && type.namespace) {
|
||||
// check (parent) namespace
|
||||
if (accessCache.has(type.namespace)) {
|
||||
access = accessCache.get(type.namespace);
|
||||
} else {
|
||||
access = getAccess(type.namespace, accessCache);
|
||||
accessCache.set(type.namespace, access);
|
||||
}
|
||||
}
|
||||
return access;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -252,15 +267,19 @@ export function isAllValueInteger(values: number[]): boolean {
|
|||
return values.every((it) => Number.isInteger(it));
|
||||
}
|
||||
|
||||
export function getUsage(type: Type | undefined): SchemaContext[] | undefined {
|
||||
export function getUsage(
|
||||
type: Type | undefined,
|
||||
usageCache: Map<Namespace, SchemaContext[] | undefined>
|
||||
): SchemaContext[] | undefined {
|
||||
if (
|
||||
type &&
|
||||
(type.kind === "Model" ||
|
||||
type.kind === "Operation" ||
|
||||
type.kind === "Enum" ||
|
||||
type.kind === "Union")
|
||||
type.kind === "Union" ||
|
||||
type.kind === "Namespace")
|
||||
) {
|
||||
return getDecoratorScopedValue(type, "$usage", (it) => {
|
||||
let usage = getDecoratorScopedValue(type, "$usage", (it) => {
|
||||
const value = it.args[0].value;
|
||||
const values: EnumMember[] = [];
|
||||
const ret: SchemaContext[] = [];
|
||||
|
@ -288,6 +307,16 @@ export function getUsage(type: Type | undefined): SchemaContext[] | undefined {
|
|||
}
|
||||
return ret;
|
||||
});
|
||||
if (!usage && type.namespace) {
|
||||
// check (parent) namespace
|
||||
if (usageCache.has(type.namespace)) {
|
||||
usage = usageCache.get(type.namespace);
|
||||
} else {
|
||||
usage = getUsage(type.namespace, usageCache);
|
||||
usageCache.set(type.namespace, usage);
|
||||
}
|
||||
}
|
||||
return usage;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче