@autorest/powershell
Version:
AutoRest PowerShell Cmdlet Generator
574 lines • 33.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tweakModelPlugin = exports.tweakModelV2 = exports.titleToAzureServiceName = exports.HeaderPropertyType = exports.HeaderProperty = 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 linq_1 = require("@azure-tools/linq");
const model_state_1 = require("../utils/model-state");
const extension_base_1 = require("@autorest/extension-base");
exports.HeaderProperty = 'HeaderProperty';
var HeaderPropertyType;
(function (HeaderPropertyType) {
HeaderPropertyType["Header"] = "Header";
HeaderPropertyType["HeaderAndBody"] = "HeaderAndBody";
})(HeaderPropertyType || (exports.HeaderPropertyType = HeaderPropertyType = {}));
// For now, we are not dynamically changing the service-name. Instead, we would figure out a method to change it during the creation of service readme's.
function titleToAzureServiceName(title) {
const titleCamelCase = (0, codegen_1.pascalCase)((0, codegen_1.deconstruct)(title)).trim();
const serviceName = titleCamelCase
// Remove: !StartsWith(Management)AndContains(Management), Client, Azure, Microsoft, APIs, API, REST
.replace(/(?!^Management)(?=.*)Management|Client|Azure|Microsoft|APIs|API|REST/g, '')
// Remove: EndsWith(ServiceResourceProvider), EndsWith(ResourceProvider), EndsWith(DataPlane), EndsWith(Data)
.replace(/ServiceResourceProvider$|ResourceProvider$|DataPlane$|Data$/g, '');
return serviceName || titleCamelCase;
}
exports.titleToAzureServiceName = titleToAzureServiceName;
function dropDuplicatePropertiesInChildSchemas(schema, state, map = new Map()) {
var _a, _b;
let success = true;
for (const parent of (0, linq_1.values)((_a = schema.parents) === null || _a === void 0 ? void 0 : _a.immediate)) {
//handle parents first
if (!dropDuplicatePropertiesInChildSchemas(parent, state, map)) {
return false;
}
}
for (const { key: id, value: property } of (0, linq_1.items)(schema.properties)) {
//see if it's in the parent.
const pProp = map.get(property.serializedName);
if (pProp) {
//if the parent prop is the same type as the child prop
//we're going to drop the child property.
if (pProp.schema.type === property.schema.type) {
//if it's an object type, it has to be the exact same schema type too
if (pProp.schema.type != codemodel_1.SchemaType.Object || pProp.schema === property.schema) {
state.verbose(`Property '${property.serializedName}' in '${schema.language.default.name}' has a property the same as the parent, and is dropping the duplicate.`, {});
if (schema.properties) {
delete schema.properties[id];
}
}
else {
const conflict = `Property '${property.serializedName}' in '${schema.language.default.name}' has a conflict with a parent schema (allOf ${(_b = schema.parents) === null || _b === void 0 ? void 0 : _b.immediate.joinWith(each => each.language.default.name)}.`;
state.error(conflict, [], {});
success = false;
}
}
}
else {
map.set(property.serializedName, property);
}
}
return success;
}
async function tweakModelV2(state) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
const title = (0, codegen_1.pascalCase)((0, codegen_1.fixLeadingNumber)((0, codegen_1.deconstruct)(await state.getValue('title', state.model.info.title))));
state.setValue('title', title);
const serviceName = await state.getValue('service-name', titleToAzureServiceName(title));
state.setValue('service-name', serviceName);
const model = state.model;
const schemas = model.schemas;
// xichen: do we need other schema types?
const allSchemas = [...(_a = schemas.objects) !== null && _a !== void 0 ? _a : [], ...(_b = schemas.choices) !== null && _b !== void 0 ? _b : [], ...(_c = schemas.sealedChoices) !== null && _c !== void 0 ? _c : []];
model.commands = {
operations: new linq_1.Dictionary(),
parameters: new linq_1.Dictionary(),
};
// we're going to create a schema that represents the distinct sum
// of all operation PATH parameters
const universalId = new codemodel_1.ObjectSchema(`${serviceName}Identity`, '');
// xichen: Add 'universal-parameter-type' in language.default.uid, so that we can find it later
universalId.language.default.uid = 'universal-parameter-type';
universalId.apiVersions = universalId.apiVersions || [];
state.model.schemas.objects = state.model.schemas.objects || [];
universalId.language.default.uid = 'universal-parameter-type';
state.model.schemas.objects.push(universalId);
for (const group of (0, linq_1.values)(model.operationGroups)) {
for (const operation of (0, linq_1.values)(group.operations)) {
for (const response of (0, linq_1.values)(operation.responses)) {
// Mark returned object in response
const respSchema = response.schema;
if ((respSchema === null || respSchema === void 0 ? void 0 : respSchema.type) === codemodel_1.SchemaType.Object) {
respSchema.extensions = respSchema.extensions || {};
respSchema.extensions['is-return-object'] = true;
}
}
for (const param of (0, linq_1.values)(operation.parameters).where(each => { var _a, _b; return ((_b = (_a = each.protocol) === null || _a === void 0 ? void 0 : _a.http) === null || _b === void 0 ? void 0 : _b.in) === codemodel_1.ParameterLocation.Path; })) {
const name = param.language.default.name;
const hasName = (_d = universalId.properties) === null || _d === void 0 ? void 0 : _d.find((prop) => prop.language.default.name.toLocaleLowerCase() === name.toLocaleLowerCase());
if (!hasName) {
if (!universalId.properties) {
universalId.properties = [];
}
const newProp = new codemodel_1.Property(name, param.language.default.description, param.schema);
newProp.required = false;
newProp.readOnly = false;
newProp.serializedName = param.language.default.serializedName;
universalId.properties.push(newProp);
}
}
}
}
if (await state.getValue('azure', false)) {
const idScheam = new codemodel_1.Schema('_identity_type_', 'Resource identity path', codemodel_1.SchemaType.String);
const idProp = new codemodel_1.Property('id', 'Resource identity path', idScheam);
idProp.readOnly = false;
idProp.required = false;
idProp.language.default.uid = 'universal-parameter:resource identity';
if (!universalId.properties) {
universalId.properties = [];
}
universalId.properties.push(idProp);
}
// xichen: do nothing in m3 logic. Comment it out
// if an operation has a response that has a schema with string/binary we should make the response application/octet-stream
// for (const operationGroups of values(model.operationGroups)) {
// for (const operation of values(operationGroups.operations)) {
// for (const response of values(operation.responses)) {
// if ((response as any).schema) {
// const respSchema = response as any;
// if (respSchema.type === SchemaType.String && respSchema.format === StringFormat.Binary) {
// // WHY WAS THIS HERE?!
// // response.mimeTypes = [KnownMediaType.Stream];
// }
// }
// }
// }
// }
// schemas that have parents and implement properties that are in the parent schemas
// will have the property dropped in the child schema
for (const schema of (0, linq_1.values)(model.schemas.objects)) {
if ((0, linq_1.length)((_e = schema.parents) === null || _e === void 0 ? void 0 : _e.immediate) > 0) {
if (!dropDuplicatePropertiesInChildSchemas(schema, state)) {
throw new Error('Schemas are in conflict.');
}
}
}
if (await state.getValue('use-storage-pipeline', false)) {
// we're going to create new models for the reponse headers ?
}
else {
// if an operation has a body parameter with string/binary, we should make the request application/octet-stream
// === Header Schemas ===
// go thru the operations, find responses that have header values, and add a property to the schemas that are returned with those values
for (const operationGroups of (0, linq_1.values)(model.operationGroups)) {
for (const operation of (0, linq_1.values)(operationGroups.operations)) {
for (const response of (0, linq_1.values)(operation.responses)) {
// for a given response, find the possible models that can be returned from the service
for (const header of (0, linq_1.values)((_f = response.protocol.http) === null || _f === void 0 ? void 0 : _f.headers)) {
if (!response.schema) {
// no response schema? can we fake one?
// service.message{ Channel: Channel.Debug, Text: `${header.key} is in ${operation.details.default.name} but there is no response model` });
continue;
}
// if the method response has a schema and it's an object, we're going to add our properties to the schema object.
// yes, this means that the reponse model may have properties that are undefined if the server doesn't send back the header
// and other operations might add other headers that are not the same.
// if the method's response is a primitive value (string, boolean, null, number) or an array, we can't modify that type obviously
// in which case, we're going to add a header
// work with schemas that have objects only.
if (response.schema.type === codemodel_1.SchemaType.Object) {
const respSchema = (response.schema);
const curHeader = header;
const headerKey = curHeader.header;
respSchema.language.default.hasHeaders = true;
const property = (0, linq_1.values)((0, codemodel_1.getAllProperties)(respSchema)).first((each) => each.language.default.name === headerKey);
if (!property) {
state.message({ Channel: extension_base_1.Channel.Debug, Text: `Adding header property '${headerKey}' to model ${respSchema.language.default.name}` });
// create a property for the header value
const newProperty = new codemodel_1.Property(headerKey, curHeader.description || '', curHeader.schema);
newProperty.language.default.required = false;
// mark it that it's a header-only property
newProperty.language.default[exports.HeaderProperty] = HeaderPropertyType.Header;
// add it to this model.
if (!respSchema.properties) {
respSchema.properties = [];
}
respSchema.properties.push(newProperty);
}
else {
// there is a property with this name already.
// was this previously declared as a header only property?
if (!property.language.default[exports.HeaderProperty]) {
state.message({ Channel: extension_base_1.Channel.Debug, Text: `Property ${headerKey} in model ${respSchema.language.default.name} can also come from the header.` });
// no.. There is duplication between header and body property. Probably because of etags.
// tell it to be a header-and-body property.
property.language.default[exports.HeaderProperty] = HeaderPropertyType.HeaderAndBody;
property.language.default.name = headerKey;
}
}
}
}
}
}
}
}
// remove well-known header parameters from operations and add mark the operation has supporting that feature
for (const operationGroups of (0, linq_1.values)(model.operationGroups)) {
for (const operation of (0, linq_1.values)(operationGroups.operations)) {
// if we have an operation with a body, and content-type is a multipart/formdata
// then we should go thru the parameters of the body and look for a string/binary parameters
// and remember to add another parameter for the filename of the string/binary
const request = (_g = operation.requests) === null || _g === void 0 ? void 0 : _g[0];
(_h = request === null || request === void 0 ? void 0 : request.parameters) === null || _h === void 0 ? void 0 : _h.filter((param) => { var _a, _b; return param.schema.type !== codemodel_1.SchemaType.Object && ((_a = param.protocol.http) === null || _a === void 0 ? void 0 : _a.in) === 'body' && ((_b = param.protocol.http) === null || _b === void 0 ? void 0 : _b.style) === codegen_1.KnownMediaType.Multipart; }).forEach((param) => {
for (const prop of (0, linq_1.values)((0, codemodel_1.getAllProperties)(param.schema))) {
if (prop.schema.type === codemodel_1.SchemaType.Binary) {
prop.language.default.isNamedStream = true;
}
}
});
// move well-known hearder parameters into details, and we can process them in the generator how we please.
// operation.details.default.headerparameters = values(operation.parameters).where(p => p.in === ParameterLocation.Header && ['If-Match', 'If-None-Match'].includes(p.name)).toArray();
// remove if-match and if-none-match parameters from the operation itself.
// operation.parameters = values(operation.parameters).where(p => !(p.in === ParameterLocation.Header && ['If-Match', 'If-None-Match'].includes(p.name))).toArray();
}
}
// identify models that are polymorphic in nature
for (const schema of allSchemas) {
if (schema instanceof codemodel_1.ObjectSchema) {
const objSchema = schema;
// if this actual type is polymorphic, make sure we know that.
// parent class
if (objSchema.discriminator) {
objSchema.language.default.isPolymorphic = true;
if (objSchema.children) {
objSchema.language.default.polymorphicChildren = (_j = objSchema.children) === null || _j === void 0 ? void 0 : _j.all;
}
}
// sub class
if (objSchema.discriminatorValue) {
objSchema.language.default.discriminatorValue = (_k = objSchema.extensions) === null || _k === void 0 ? void 0 : _k['x-ms-discriminator-value'];
}
}
}
// identify parameters that are constants
for (const group of (0, linq_1.values)(model.operationGroups)) {
for (const operation of (0, linq_1.values)(group.operations)) {
for (const parameter of (0, linq_1.values)(operation.parameters)) {
if (parameter.required) {
if (parameter.schema.type === codemodel_1.SchemaType.Choice) {
const choiceSchema = parameter.schema;
if (choiceSchema.choices.length === 1) {
parameter.language.default.constantValue = choiceSchema.choices[0].value;
}
}
else if (parameter.schema.type === codemodel_1.SchemaType.Constant) {
const constantSchema = parameter.schema;
parameter.language.default.constantValue = constantSchema.value.value;
}
else if (parameter.schema.type === codemodel_1.SchemaType.SealedChoice) {
const sealedChoiceSchema = parameter.schema;
if (sealedChoiceSchema.choices.length === 1) {
parameter.language.default.constantValue = sealedChoiceSchema.choices[0].value;
if (sealedChoiceSchema.language.default.skip !== false) {
sealedChoiceSchema.language.default.skip = true;
}
}
}
}
else {
if (parameter.schema.type === codemodel_1.SchemaType.SealedChoice) {
const sealedChoiceSchema = parameter.schema;
if (sealedChoiceSchema.choices.length === 1) {
sealedChoiceSchema.language.default.skip = false;
}
}
}
}
}
}
// identify properties that are constants
for (const schema of (0, linq_1.values)(schemas.objects)) {
for (const property of (0, linq_1.values)(schema.properties)) {
if (property === undefined) {
continue;
}
if (property.required) {
if (property.schema.type === codemodel_1.SchemaType.Choice) {
const choiceSchema = property.schema;
if (choiceSchema.choices.length === 1) {
// properties with an enum single value are constants
// add the constant value
property.language.default.constantValue = choiceSchema.choices[0].value;
}
}
else if (property.schema.type === codemodel_1.SchemaType.Constant) {
const constantSchema = property.schema;
property.language.default.constantValue = constantSchema.value.value;
}
else if (property.schema.type === codemodel_1.SchemaType.SealedChoice) {
const sealedChoiceSchema = property.schema;
if (sealedChoiceSchema.choices.length === 1) {
property.language.default.constantValue = sealedChoiceSchema.choices[0].value;
if (sealedChoiceSchema.language.default.skip !== false) {
sealedChoiceSchema.language.default.skip = true;
}
}
}
}
else {
if (property.schema.type === codemodel_1.SchemaType.SealedChoice) {
const sealedChoiceSchema = property.schema;
if (sealedChoiceSchema.choices.length === 1) {
sealedChoiceSchema.language.default.skip = false;
}
}
}
}
}
// xichen: Do we need skip?
// const enumsToSkip = new Set<string>();
// // identify properties that are constants
// for (const schema of values(model.schemas)) {
// for (const property of values(schema.properties)) {
// if (property.details.default.required && length(property.schema.enum) === 1) {
// // properties with an enum single value are constants
// // add the constant value
// property.details.default.constantValue = property.schema.enum[0];
// // mark as skip the generation of this model
// enumsToSkip.add(property.schema.details.default.uid);
// // make it a string and keep its name
// property.schema = new Schema(property.schema.details.default.name, { type: property.schema.type });
// } else {
// enumsToSkip.delete(property.schema.details.default.uid);
// }
// }
// }
// // mark enums that shouldn't be generated
// for (const schema of values(model.schemas)) {
// if (enumsToSkip.has(schema.details.default.uid)) {
// schema.details.default.skip = true;
// }
// }
return model;
}
exports.tweakModelV2 = tweakModelV2;
// async function tweakModel(state: State): Promise<codemodel.Model> {
// const title = pascalCase(fixLeadingNumber(deconstruct(await state.getValue('title', state.model.info.title))));
// state.setValue('title', title);
// const serviceName = await state.getValue('service-name', titleToAzureServiceName(title));
// state.setValue('service-name', serviceName);
// const model = state.model;
// model.schemas = model.schemas || [];
// const set = new Set<Schema>();
// const removes = new Set<string>();
// for (const key of keys(model.schemas)) {
// const value = model.schemas[key];
// if (set.has(value)) {
// // this schema is already in the collection. let's drop it when we're done
// removes.add(key);
// } else {
// set.add(value);
// }
// }
// // we're going to create a schema that represents the distinct sum
// // of all operation PATH parameters
// const universalId = new Schema(`${serviceName}Identity`, {
// type: JsonType.Object, description: 'Resource Identity', details: {
// default: {
// uid: 'universal-parameter-type'
// }
// }
// });
// model.schemas['universal-parameter-type'] = universalId;
// for (const operation of values(model.http.operations)) {
// for (const param of values(operation.parameters).where(each => each.in === ParameterLocation.Path)) {
// const name = param.details.default.name;
// if (!universalId.properties[name]) {
// universalId.properties[name] = new Property(name, {
// schema: param.schema, description: param.description, serializedName: name, details: {
// default: {
// description: param.description,
// name: name,
// required: false,
// readOnly: false,
// uid: `universal-parameter:${name}`
// }
// }
// });
// }
// }
// }
// if (await state.getValue('azure', false)) {
// universalId.properties['id'] = new Property('id', {
// schema: new Schema('_identity_type_', { type: JsonType.String, description: 'Resource identity path' }),
// description: 'Resource identity path', serializedName: 'id', details: {
// default: {
// description: 'Resource identity path',
// name: 'id',
// required: false,
// readOnly: false,
// uid: 'universal-parameter:resource identity'
// }
// }
// });
// }
// // remove schemas that are referenced elsewhere previously.
// for (const each of removes.values()) {
// delete model.schemas[each];
// }
// // if an operation has a response that has a schema with string/binary we should make the response application/octet-stream
// for (const operation of values(model.http.operations)) {
// for (const responses of values(operation.responses)) {
// for (const response of responses) {
// if (response.schema) {
// if (response.schema.type === JsonType.String && response.schema.format === StringFormat.Binary) {
// // WHY WAS THIS HERE?!
// // response.mimeTypes = [KnownMediaType.Stream];
// }
// }
// }
// }
// }
// // schemas that have parents and implement properties that are in the parent schemas
// // will have the property dropped in the child schema
// for (const schema of values(model.schemas)) {
// if (length(schema.allOf) > 0) {
// if (!dropDuplicatePropertiesInChildSchemas(schema, state)) {
// throw new Error('Schemas are in conflict.');
// }
// }
// }
// if (await state.getValue('use-storage-pipeline', false)) {
// // we're going to create new models for the reponse headers ?
// } else {
// // if an operation has a body parameter with string/binary, we should make the request application/octet-stream
// // === Header Schemas ===
// // go thru the operations, find responses that have header values, and add a property to the schemas that are returned with those values
// for (const operation of values(model.http.operations)) {
// for (const responses of values(operation.responses)) {
// for (const response of responses) {
// // for a given response, find the possible models that can be returned from the service
// for (const header of values(response.headers)) {
// if (!response.schema) {
// // no response schema? can we fake one?
// // service.message{ Channel: Channel.Debug, Text: `${header.key} is in ${operation.details.default.name} but there is no response model` });
// continue;
// }
// // if the method response has a schema and it's an object, we're going to add our properties to the schema object.
// // yes, this means that the reponse model may have properties that are undefined if the server doesn't send back the header
// // and other operations might add other headers that are not the same.
// // if the method's response is a primitive value (string, boolean, null, number) or an array, we can't modify that type obviously
// // in which case, we're going to add a header
// // work with schemas that have objects only.
// if (isSchemaObject(response.schema)) {
// response.schema.details.default.hasHeaders = true;
// const property = response.schema.properties[header.key];
// if (!property) {
// state.message({ Channel: Channel.Debug, Text: `Adding header property '${header.key}' to model ${response.schema.details.default.name}` });
// // create a property for the header value
// const newProperty = new Property(header.key, { schema: header.schema, description: header.description });
// newProperty.details.default.name = header.key;
// newProperty.details.default.required = false;
// // mark it that it's a header-only property
// newProperty.details.default[HeaderProperty] = HeaderPropertyType.Header;
// // add it to this model.
// response.schema.properties[header.key] = newProperty;
// } else {
// // there is a property with this name already.
// // was this previously declared as a header only property?
// if (!property.details.default[HeaderProperty]) {
// state.message({ Channel: Channel.Debug, Text: `Property ${header.key} in model ${response.schema.details.default.name} can also come from the header.` });
// // no.. There is duplication between header and body property. Probably because of etags.
// // tell it to be a header-and-body property.
// property.details.default[HeaderProperty] = HeaderPropertyType.HeaderAndBody;
// property.details.default.name = header.key;
// }
// }
// }
// }
// }
// }
// }
// }
// // remove well-known header parameters from operations and add mark the operation has supporting that feature
// for (const operation of values(model.http.operations)) {
// // if we have an operation with a body, and content-type is a multipart/formdata
// // then we should go thru the parameters of the body and look for a string/binary parameters
// // and remember to add another parameter for the filename of the string/binary
// if (operation.requestBody && knownMediaType(operation.requestBody.contentType) === KnownMediaType.Multipart) {
// for (const prop of values(operation.requestBody.schema.properties)) {
// if (prop.schema.type === JsonType.String && prop.schema.format === 'binary') {
// prop.details.default.isNamedStream = true;
// }
// }
// }
// // move well-known hearder parameters into details, and we can process them in the generator how we please.
// // operation.details.default.headerparameters = values(operation.parameters).where(p => p.in === ParameterLocation.Header && ['If-Match', 'If-None-Match'].includes(p.name)).toArray();
// // remove if-match and if-none-match parameters from the operation itself.
// // operation.parameters = values(operation.parameters).where(p => !(p.in === ParameterLocation.Header && ['If-Match', 'If-None-Match'].includes(p.name))).toArray();
// }
// // identify models that are polymorphic in nature
// for (const schema of values(model.schemas)) {
// // if this actual type is polymorphic, make sure we know that.
// if (schema.discriminator) {
// schema.details.default.isPolymorphic = true;
// }
// const parents = getPolymorphicBases(schema);
// if (length(parents) > 0) {
// // if our parent is polymorphic, then we must have a discriminator value
// schema.details.default.discriminatorValue = schema.extensions['x-ms-discriminator-value'] || schema.details.default.name;
// // and make sure that all our polymorphic parents have a reference to this type.
// for (const parent of getPolymorphicBases(schema)) {
// parent.details.default.polymorphicChildren = parent.details.default.polymorphicChildren || new Array<Schema>();
// parent.details.default.polymorphicChildren.push(schema);
// }
// }
// }
// // identify parameters that are constants
// for (const operation of values(model.http.operations)) {
// for (const parameter of values(operation.parameters)) {
// if (parameter.required && length(parameter.schema.enum) === 1) {
// // parameters with an enum single value are constants
// parameter.details.default.constantValue = parameter.schema.enum[0];
// }
// }
// }
// const enumsToSkip = new Set<string>();
// // identify properties that are constants
// for (const schema of values(model.schemas)) {
// for (const property of values(schema.properties)) {
// if (property.details.default.required && length(property.schema.enum) === 1) {
// // properties with an enum single value are constants
// // add the constant value
// property.details.default.constantValue = property.schema.enum[0];
// // mark as skip the generation of this model
// enumsToSkip.add(property.schema.details.default.uid);
// // make it a string and keep its name
// property.schema = new Schema(property.schema.details.default.name, { type: property.schema.type });
// } else {
// enumsToSkip.delete(property.schema.details.default.uid);
// }
// }
// }
// // mark enums that shouldn't be generated
// for (const schema of values(model.schemas)) {
// if (enumsToSkip.has(schema.details.default.uid)) {
// schema.details.default.skip = true;
// }
// }
// for (const operation of values(model.http.operations)) {
// for (const { key: responseCode, value: responses } of items(operation.responses)) {
// for (const response of values(responses)) {
// if (responseCode === 'default' || response.extensions['x-ms-error-response'] === true) {
// response.details.default.isErrorResponse = true;
// }
// }
// }
// }
// return model;
// }
// Universal version -
// tweaks the code model to adjust things so that the code will generate better.
async function tweakModelPlugin(service) {
//const session = await startSession<PwshModel>(service, {}, codeModelSchema);
const state = await new model_state_1.ModelState(service).init();
//const result = tweakModelV2(session);
await service.writeFile({ filename: 'code-model-v4-tweakcodemodel-v2.yaml', content: (0, codegen_1.serialize)(await tweakModelV2(state)), sourceMap: undefined, artifactType: 'code-model-v4' });
//return processCodeModel(tweakModelV2, service, 'tweakcodemodel-v2');
}
exports.tweakModelPlugin = tweakModelPlugin;
//# sourceMappingURL=plugin-tweak-model.js.map