UNPKG

@autorest/powershell

Version:
196 lines 10.1 kB
"use strict"; 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