@autorest/powershell
Version:
AutoRest PowerShell Cmdlet Generator
196 lines • 10.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.tweakM4ModelPlugin = exports.tweakModelForTsp = exports.directives = void 0;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const codemodel_1 = require("@autorest/codemodel");
const codegen_1 = require("@azure-tools/codegen");
const model_state_1 = require("../utils/model-state");
const http_definitions_1 = require("../utils/http-definitions");
const linq_1 = require("@azure-tools/linq");
const sort_parameters_1 = require("../utils/sort-parameters");
exports.directives = [];
async function tweakModelForTsp(state) {
const allDirectives = await state.service.getValue('directive');
exports.directives = (0, linq_1.values)(allDirectives).toArray();
return await tweakModel(state);
}
exports.tweakModelForTsp = tweakModelForTsp;
async function tweakModel(state) {
const model = state.model;
sortParameters(model);
addResponseHeaderSchema(model);
addDictionaryApiVersion(model);
removeM4DefaultDescription(model);
removeExceptionResponse(model);
handleNoinlineDirective(state);
return model;
}
//remove error responses except default
function removeExceptionResponse(model) {
model.operationGroups.forEach(group => {
var _a;
(_a = group.operations) === null || _a === void 0 ? void 0 : _a.forEach(operation => {
var _a;
operation.exceptions = (_a = operation.exceptions) === null || _a === void 0 ? void 0 : _a.filter(exception => { var _a; return ((_a = exception.protocol.http) === null || _a === void 0 ? void 0 : _a.statusCodes[0]) === 'default'; });
});
});
}
//sort path parameters to follow the order in path for each operation
function sortParameters(model) {
model.operationGroups.forEach(group => {
var _a;
(_a = group.operations) === null || _a === void 0 ? void 0 : _a.forEach(operation => {
var _a, _b;
operation.parameters = (0, sort_parameters_1.sortPathParameters)((_b = (_a = operation.requests) === null || _a === void 0 ? void 0 : _a[0].protocol.http) === null || _b === void 0 ? void 0 : _b.path, operation.parameters);
});
});
}
function handleNoinlineDirective(state) {
let inlineModels = [];
for (const directive of exports.directives.filter(each => each['no-inline'])) {
inlineModels = inlineModels.concat((0, linq_1.values)(directive['no-inline']).toArray());
}
for (const model of state.model.schemas.objects || []) {
if (inlineModels.includes(model.language.default.name)) {
model.language.default['skip-inline'] = true;
}
}
}
function addResponseHeaderSchema(model) {
// In remodeler, each operations response headers will has its own scheam. Each header will be schema's property.
// But in m4, if 'schema' is not explicitly defined, even 'headers' is specified, there won't be a schema for headers.
// To keep backward compatiable, we will create headers schema here
model.operationGroups.forEach((group) => {
var _a;
(_a = group.operations) === null || _a === void 0 ? void 0 : _a.forEach((op) => {
if (!op.responses) {
return;
}
op.responses.forEach((resp) => {
var _a, _b, _c, _d;
if (resp.schema) {
return;
}
const headers = (_a = resp.protocol.http) === null || _a === void 0 ? void 0 : _a.headers;
if (headers === undefined) {
return;
}
const responseCode = (_c = (_b = resp.protocol.http) === null || _b === void 0 ? void 0 : _b.statusCodes) === null || _c === void 0 ? void 0 : _c[0];
if (responseCode === undefined) {
return;
}
// Follow naming pattern in m3
const code = (http_definitions_1.StatusCodes[responseCode] || '') || responseCode;
const schemaName = `${group.language.default.name}_${op.language.default.name} ${code} ResponseHeaders`;
const newSchema = ((_d = model.schemas.objects) === null || _d === void 0 ? void 0 : _d.find((schema) => schema.language.default.name === schemaName)) ||
new codemodel_1.ObjectSchema(schemaName, '');
newSchema.language.default.isHeaderModel = true;
if (!model.schemas.objects) {
model.schemas.objects = [];
}
model.schemas.objects.push(newSchema);
headers.forEach((head) => {
// We lost description and x-ms-client-name in m4. So newProp's description is empty and use header as serializedName
const newProp = new codemodel_1.Property(head.header, '', head.schema, {
readOnly: false,
required: false,
serializedName: head.header
});
newProp.language.default.HeaderProperty = 'Header';
if (!newSchema.properties) {
newSchema.properties = [];
}
newSchema.properties.push(newProp);
});
// Set response header use new schema
resp.language.default.headerSchema = newSchema;
});
});
});
}
function addDictionaryApiVersion(model) {
var _a, _b;
(_a = model.schemas.dictionaries) === null || _a === void 0 ? void 0 : _a.forEach((schema) => {
if (schema.apiVersions) {
return;
}
if (schema.elementType && schema.elementType.apiVersions) {
schema.apiVersions = JSON.parse(JSON.stringify(schema.elementType.apiVersions));
}
});
// If we cannot find api version from element type, try to get it from object schema who refers the dict or any.
(_b = model.schemas.objects) === null || _b === void 0 ? void 0 : _b.forEach((schema) => {
var _a;
if (!schema.apiVersions) {
return;
}
for (const prop of (0, codemodel_1.getAllProperties)(schema)) {
if (prop.schema.type !== codemodel_1.SchemaType.Dictionary || prop.schema.apiVersions) {
continue;
}
prop.schema.apiVersions = JSON.parse(JSON.stringify(schema.apiVersions));
}
if (schema.parents) {
for (const parent of (((_a = schema.parents) === null || _a === void 0 ? void 0 : _a.all) || [])) {
if (parent.type !== codemodel_1.SchemaType.Dictionary || parent.apiVersions) {
continue;
}
// for object which both contains properties and additional properties,
// we need to skip the model generation for redundant dict.
parent.language.default.skip = true;
}
}
});
}
function removeM4DefaultDescription(model) {
// For dictionary and arrya schema and property, if there is no description assigned, m4 will set a default description like: Dictionary of <type> or Array of <type>
// To keep same action as m3, we will set it to empty string
var _a, _b, _c;
const visited = new Set();
[...(_a = model.schemas.objects) !== null && _a !== void 0 ? _a : [], ...(_b = model.schemas.dictionaries) !== null && _b !== void 0 ? _b : [], ...(_c = model.schemas.arrays) !== null && _c !== void 0 ? _c : []].forEach((schema) => {
recursiveRemoveM4DefaultDescription(schema, visited);
});
}
function recursiveRemoveM4DefaultDescription(schema, visited) {
if (visited.has(schema) || (schema.type !== codemodel_1.SchemaType.Object && schema.type !== codemodel_1.SchemaType.Dictionary && schema.type !== codemodel_1.SchemaType.Array)) {
return;
}
// Default description pattern in m4
const defaultDictDescPattern = /Dictionary of <.?>$/;
const defaultArrayDescPattern = /Array of .?$/;
visited.add(schema);
if (schema.type === codemodel_1.SchemaType.Dictionary) {
const dictSchema = schema;
recursiveRemoveM4DefaultDescription(dictSchema.elementType, visited);
if (defaultDictDescPattern.test(dictSchema.language.default.description)) {
dictSchema.language.default.description = '';
}
}
else if (schema.type === codemodel_1.SchemaType.Array) {
const arrSchema = schema;
recursiveRemoveM4DefaultDescription(arrSchema.elementType, visited);
if (defaultArrayDescPattern.test(schema.language.default.description)) {
schema.language.default.description = '';
}
}
else if (schema.type === codemodel_1.SchemaType.Object) {
const objSchema = schema;
for (const prop of (0, codemodel_1.getAllProperties)(objSchema)) {
recursiveRemoveM4DefaultDescription(prop.schema, visited);
if (prop.schema.type === codemodel_1.SchemaType.Dictionary && (defaultDictDescPattern.test(prop.language.default.description) || defaultArrayDescPattern.test(prop.language.default.description))) {
prop.language.default.description = '';
}
}
}
}
async function tweakM4ModelPlugin(service) {
const allDirectives = await service.getValue('directive');
exports.directives = (0, linq_1.values)(allDirectives).toArray();
const state = await new model_state_1.ModelState(service).init();
service.writeFile({ filename: 'code-model-v4-tweakm4codemodel.yaml', content: (0, codegen_1.serialize)(await tweakModel(state)), sourceMap: undefined, artifactType: 'code-model-v4' });
}
exports.tweakM4ModelPlugin = tweakM4ModelPlugin;
//# sourceMappingURL=plugin-tweak-m4-model.js.map