UNPKG

@rxap/ts-morph

Version:

Provides utilities for manipulating TypeScript code using the ts-morph library. It offers a fluent API to add, modify, and remove code elements such as classes, decorators, imports, and properties in both Angular and NestJS projects. This package simplifi

237 lines 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CoerceDtoClass = CoerceDtoClass; const utilities_1 = require("@rxap/utilities"); const path_1 = require("path"); const ts_morph_1 = require("ts-morph"); const dto_class_property_1 = require("./dto-class-property"); require("colors"); const coerce_source_file_1 = require("../coerce-source-file"); const coerce_class_1 = require("../coerce-class"); const type_import_1 = require("../type-import"); const coerce_property_declaration_1 = require("../coerce-property-declaration"); const write_type_1 = require("../write-type"); const coerce_decorator_1 = require("../coerce-decorator"); const coerce_imports_1 = require("../coerce-imports"); function CoerceDtoClass(options) { const { project, propertyList = [], tsMorphTransform = utilities_1.noop, } = options; let { name, } = options; name = (0, utilities_1.dasherize)(name); const className = (0, utilities_1.CoerceSuffix)((0, utilities_1.classify)(name), 'Dto'); const fileName = (0, utilities_1.CoerceSuffix)(name, '.dto'); const sourceFile = (0, coerce_source_file_1.CoerceSourceFile)(project, (0, path_1.join)('dtos', fileName + '.ts')); const classDeclaration = (0, coerce_class_1.CoerceClass)(sourceFile, className); classDeclaration.setIsExported(true); for (const property of propertyList.map(dto_class_property_1.NormalizeDataClassProperty)) { // create a clone of the property type to avoid modifying the original type // if the property type is a self reference we need to replace the self reference with the class name // if the property type is a deferred reference we need to replace the deferred reference with the class name const propertyType = Object.assign({}, property.type); let subTypeOutput; switch (propertyType.name) { case type_import_1.TypeNames.Self: propertyType.name = className; propertyType.isTypeOnly = false; propertyType.moduleSpecifier = null; propertyType.namedImport = null; propertyType.namespaceImport = null; propertyType.defaultImport = null; property.isType = true; break; case type_import_1.TypeNames.Deferred: subTypeOutput = CoerceDtoClass({ project, name: [name, (0, utilities_1.dasherize)(property.name)].join('-'), propertyList: property.memberList, }); propertyType.name = subTypeOutput.className; propertyType.moduleSpecifier = './' + (0, utilities_1.dasherize)(subTypeOutput.className.replace(/Dto$/, '')) + '.dto'; propertyType.isTypeOnly = false; propertyType.namedImport = null; propertyType.namespaceImport = null; propertyType.defaultImport = null; property.isType = true; break; } let propertyName = (0, utilities_1.camelize)(property.name); const prefixMatch = property.name.match(/^(_+)/); if (prefixMatch) { propertyName = (0, utilities_1.camelize)(property.name.replace(/^_+/, '')); propertyName = prefixMatch[0] + propertyName; } const propertyDeclaration = (0, coerce_property_declaration_1.CoercePropertyDeclaration)(classDeclaration, propertyName).set({ type: (0, write_type_1.WriteType)({ isArray: property.isArray, type: propertyType, }, sourceFile), hasQuestionToken: property.isOptional, hasExclamationToken: !property.isOptional, }); addExposeDecorator(propertyDeclaration); if (property.isArray) { addClassValidatorDecoratorForIsArray(propertyDeclaration); } if (property.isType) { addClassValidatorDecoratorForNestedDto(propertyDeclaration, propertyType, property.isArray); } if (property.isOptional) { addIsOptionalDecorator(propertyDeclaration); } addClassValidatorDecoratorForType(propertyDeclaration, propertyType); if (propertyType.name !== 'unknown') { cleanupUnknownApiPropertyDecorator(propertyDeclaration); } } tsMorphTransform(project, sourceFile, classDeclaration); return { className, filePath: '.' + (0, path_1.join)(sourceFile.getDirectoryPath(), sourceFile.getBaseNameWithoutExtension()), sourceFile, classDeclaration, }; } function addIsOptionalDecorator(propertyDeclaration) { const sourceFile = propertyDeclaration.getSourceFile(); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsOptional', { arguments: [], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsOptional'], moduleSpecifier: 'class-validator', }); } function addExposeDecorator(propertyDeclaration) { const sourceFile = propertyDeclaration.getSourceFile(); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'Expose', { arguments: [], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['Expose'], moduleSpecifier: 'class-transformer', }); } function addClassValidatorDecoratorForIsArray(propertyDeclaration) { const sourceFile = propertyDeclaration.getSourceFile(); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsArray', { arguments: [], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsArray'], moduleSpecifier: 'class-validator', }); } function addClassValidatorDecoratorForNestedDto(propertyDeclaration, propertyType, isArray) { const sourceFile = propertyDeclaration.getSourceFile(); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'Type', { arguments: [ w => { w.write('() => '); (0, write_type_1.WriteType)({ type: propertyType, isArray: false, }, sourceFile)(w); }, ], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['Type'], moduleSpecifier: 'class-transformer', }); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsInstance', { arguments: [ (0, write_type_1.WriteType)({ type: propertyType, isArray: false, }, sourceFile), w => { if (isArray) { ts_morph_1.Writers.object({ each: 'true' })(w); } }, ], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsInstance'], moduleSpecifier: 'class-validator', }); } function addClassValidatorDecoratorForType(propertyDeclaration, propertyType) { var _a; const sourceFile = propertyDeclaration.getSourceFile(); switch (propertyType.name) { case 'date': (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsDate', { arguments: [], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsDate'], moduleSpecifier: 'class-validator', }); break; case 'number': (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsNumber', { arguments: [], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsNumber'], moduleSpecifier: 'class-validator', }); break; case 'string': if ((_a = propertyDeclaration.getName()) === null || _a === void 0 ? void 0 : _a.match(/^uuid|Uuid$/)) { (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsUUID'], moduleSpecifier: 'class-validator', }); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsUUID', { arguments: [], }); } else { (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsString'], moduleSpecifier: 'class-validator', }); (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsString', { arguments: [], }); } break; case 'boolean': (0, coerce_decorator_1.CoerceDecorator)(propertyDeclaration, 'IsBoolean', { arguments: [], }); (0, coerce_imports_1.CoerceImports)(sourceFile, { namedImports: ['IsBoolean'], moduleSpecifier: 'class-validator', }); break; // If the property type is unknown we should NOT add the ApiProperty decorator // case 'unknown': // CoerceDecorator( // propertyDeclaration, // 'ApiProperty', // { // arguments: [ Writers.object({ type: w => w.quote('unknown') }) ], // }, // ); // CoerceImports(sourceFile, { // namedImports: [ 'ApiProperty' ], // moduleSpecifier: '@nestjs/swagger', // }); // break; } } function cleanupUnknownApiPropertyDecorator(propertyDeclaration) { var _a; const apiProperty = propertyDeclaration.getDecorators().find(d => d.getName() === 'ApiProperty'); if (apiProperty) { const args = apiProperty.getArguments()[0]; if (args.isKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression)) { if ((_a = args.getProperty('type')) === null || _a === void 0 ? void 0 : _a.getText().includes('unknown')) { apiProperty.remove(); } } } } //# sourceMappingURL=coerce-dto-class.js.map