Skip to content

Commit

Permalink
Merge pull request #3134 from Michsior14/fix/compiler-option-paths-ma…
Browse files Browse the repository at this point in the history
…pping

fix(plugin): support compiler options paths mapping
  • Loading branch information
kamilmysliwiec authored Nov 5, 2024
2 parents 011d1af + f33ce0c commit d2eac71
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 40 deletions.
24 changes: 21 additions & 3 deletions lib/plugin/utils/plugin-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ export function getTypeReferenceAsString(
if (type.aliasSymbol) {
return { typeName: 'Object', arrayDepth };
}
if (typeChecker.getApparentType(type).getSymbol().getEscapedName() === 'String') {
if (
typeChecker.getApparentType(type).getSymbol().getEscapedName() ===
'String'
) {
return { typeName: String.name, arrayDepth };
}
return { typeName: undefined };
Expand All @@ -140,7 +143,8 @@ export function hasPropertyKey(
export function replaceImportPath(
typeReference: string,
fileName: string,
options: PluginOptions
options: PluginOptions,
compilerOptionsPaths: ts.MapLike<string[]>
) {
if (!typeReference.includes('import')) {
return { typeReference, importPath: null };
Expand All @@ -167,6 +171,19 @@ export function replaceImportPath(
? convertPath(options.pathToSource)
: posix.dirname(convertPath(fileName));

for (const [key, value] of Object.entries(compilerOptionsPaths)) {
const keyToMatch = key.replace('*', '');
if (importPath.includes(keyToMatch)) {
const newImportPath = posix.join(
from,
importPath.replace(keyToMatch, value[0].replace('*', ''))
);
typeReference = typeReference.replace(importPath, newImportPath);
importPath = newImportPath;
break;
}
}

let relativePath = posix.relative(from, importPath);
relativePath = relativePath[0] !== '.' ? './' + relativePath : relativePath;

Expand Down Expand Up @@ -250,7 +267,8 @@ export function isAutoGeneratedEnumUnion(
return undefined;
}
const undefinedTypeIndex = type.types.findIndex(
(type: any) => type.intrinsicName === 'undefined' || type.intrinsicName === 'null'
(type: any) =>
type.intrinsicName === 'undefined' || type.intrinsicName === 'null'
);
if (undefinedTypeIndex < 0) {
return undefined;
Expand Down
6 changes: 4 additions & 2 deletions lib/plugin/utils/type-reference-to-identifier.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export function typeReferenceToIdentifier(
options: PluginOptions,
factory: ts.NodeFactory,
type: ts.Type,
typeImports: Record<string, string>
typeImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
) {
if (options.readonly) {
assertReferenceableType(
Expand All @@ -27,7 +28,8 @@ export function typeReferenceToIdentifier(
const { typeReference, importPath, typeName } = replaceImportPath(
typeReferenceDescriptor.typeName,
hostFilename,
options
options,
compilerOptionsPaths
);

let identifier: ts.Identifier;
Expand Down
22 changes: 15 additions & 7 deletions lib/plugin/visitors/controller-class.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
options: PluginOptions
) {
const typeChecker = program.getTypeChecker();
const compilerOptionsPaths = program.getCompilerOptions().paths ?? {};
if (!options.readonly) {
sourceFile = this.updateImports(sourceFile, ctx.factory, program);
}
Expand All @@ -72,7 +73,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
typeChecker,
options,
sourceFile,
metadata
metadata,
compilerOptionsPaths
);
if (!options.readonly) {
return updatedNode;
Expand Down Expand Up @@ -121,7 +123,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
typeChecker: ts.TypeChecker,
options: PluginOptions,
sourceFile: ts.SourceFile,
metadata: ClassMetadata
metadata: ClassMetadata,
compilerOptionsPaths: ts.MapLike<string[]>
): ts.MethodDeclaration {
const hostFilename = sourceFile.fileName;
const decorators =
Expand Down Expand Up @@ -165,7 +168,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
factory.createNodeArray(),
hostFilename,
metadata,
options
options,
compilerOptionsPaths
);
const updatedDecorators = [
...apiOperationDecoratorsArray,
Expand Down Expand Up @@ -389,7 +393,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
existingProperties: ts.NodeArray<ts.PropertyAssignment> = factory.createNodeArray(),
hostFilename: string,
metadata: ClassMetadata,
options: PluginOptions
options: PluginOptions,
compilerOptionsPaths: ts.MapLike<string[]>
): ts.ObjectLiteralExpression {
let properties = [];
if (!options.readonly) {
Expand All @@ -405,7 +410,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
typeChecker,
existingProperties,
hostFilename,
options
options,
compilerOptionsPaths
)
]);
const objectLiteralExpr = factory.createObjectLiteralExpression(
Expand Down Expand Up @@ -435,7 +441,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
typeChecker: ts.TypeChecker,
existingProperties: ts.NodeArray<ts.PropertyAssignment>,
hostFilename: string,
options: PluginOptions
options: PluginOptions,
compilerOptionsPaths: ts.MapLike<string[]>
) {
if (hasPropertyKey('type', existingProperties)) {
return undefined;
Expand All @@ -458,7 +465,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
options,
factory,
type,
this._typeImports
this._typeImports,
compilerOptionsPaths
);
return factory.createPropertyAssignment('type', identifier);
}
Expand Down
81 changes: 54 additions & 27 deletions lib/plugin/visitors/model-class.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { posix } from 'path';
import * as ts from 'typescript';
import { factory, PropertyAssignment } from 'typescript';
import { ApiHideProperty, ApiProperty } from '../../decorators';
import {
decoratorsProperties,
decoratorsPropertiesMappingType
} from '../../services/decorators-properties';
import { PluginOptions } from '../merge-options';
import { METADATA_FACTORY_NAME } from '../plugin-constants';
import { pluginDebugLogger } from '../plugin-debug-logger';
Expand All @@ -16,6 +20,10 @@ import {
getTsDocTagsOfNode,
isEnum
} from '../utils/ast-utils';
import {
getExternalImports,
replaceExternalImportsInTypeReference
} from '../utils/external-imports.util';
import {
canReferenceNode,
convertPath,
Expand All @@ -28,14 +36,6 @@ import {
} from '../utils/plugin-utils';
import { typeReferenceToIdentifier } from '../utils/type-reference-to-identifier.util';
import { AbstractFileVisitor } from './abstract.visitor';
import {
getExternalImports,
replaceExternalImportsInTypeReference
} from '../utils/external-imports.util';
import {
decoratorsProperties,
decoratorsPropertiesMappingType
} from '../../services/decorators-properties';

type ClassMetadata = Record<string, ts.ObjectLiteralExpression>;

Expand Down Expand Up @@ -72,6 +72,7 @@ export class ModelClassVisitor extends AbstractFileVisitor {
) {
const externalImports = getExternalImports(sourceFile);
const typeChecker = program.getTypeChecker();
const compilerOptionsPaths = program.getCompilerOptions().paths ?? {};
sourceFile = this.updateImports(sourceFile, ctx.factory, program);

const propertyNodeVisitorFactory =
Expand All @@ -86,7 +87,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options,
sourceFile,
metadata,
externalImports
externalImports,
compilerOptionsPaths
);
} else if (
options.parameterProperties &&
Expand All @@ -98,7 +100,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options,
sourceFile,
metadata,
externalImports
externalImports,
compilerOptionsPaths
);
}
return node;
Expand Down Expand Up @@ -165,7 +168,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options: PluginOptions,
sourceFile: ts.SourceFile,
metadata: ClassMetadata,
externalImports: Record<string, string>
externalImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
) {
const isPropertyStatic = (node.modifiers || []).some(
(modifier: ts.Modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword
Expand Down Expand Up @@ -213,7 +217,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
sourceFile.fileName,
sourceFile,
metadata,
externalImports
externalImports,
compilerOptionsPaths
);
} catch (err) {
return node;
Expand All @@ -226,7 +231,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options: PluginOptions,
sourceFile: ts.SourceFile,
metadata: ClassMetadata,
externalImports: Record<string, string>
externalImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
) {
constructorNode.forEachChild((node) => {
if (
Expand All @@ -248,7 +254,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options,
sourceFile.fileName,
sourceFile,
externalImports
externalImports,
compilerOptionsPaths
);

const propertyName = node.name.getText();
Expand Down Expand Up @@ -315,7 +322,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
hostFilename: string,
sourceFile: ts.SourceFile,
metadata: ClassMetadata,
externalImports: Record<string, string>
externalImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
) {
const objectLiteralExpr = this.createDecoratorObjectLiteralExpr(
factory,
Expand All @@ -325,7 +333,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options,
hostFilename,
sourceFile,
externalImports
externalImports,
compilerOptionsPaths
);
this.addClassMetadata(
compilerNode,
Expand All @@ -346,7 +355,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options: PluginOptions = {},
hostFilename = '',
sourceFile?: ts.SourceFile,
externalImports: Record<string, string> = {}
externalImports: Record<string, string> = {},
compilerOptionsPaths: ts.MapLike<string[]> = {}
): ts.ObjectLiteralExpression {
const isRequired = !node.questionToken;

Expand All @@ -363,7 +373,9 @@ export class ModelClassVisitor extends AbstractFileVisitor {
typeChecker,
existingProperties,
hostFilename,
options
options,
externalImports,
compilerOptionsPaths
),
...this.createDescriptionAndTsDocTagPropertyAssignments(
factory,
Expand All @@ -386,7 +398,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
existingProperties,
hostFilename,
options,
externalImports
externalImports,
compilerOptionsPaths
)
];
if (
Expand All @@ -411,7 +424,9 @@ export class ModelClassVisitor extends AbstractFileVisitor {
typeChecker: ts.TypeChecker,
existingProperties: ts.NodeArray<ts.PropertyAssignment>,
hostFilename: string,
options: PluginOptions
options: PluginOptions,
externalImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
): ts.PropertyAssignment[] {
const key = 'type';
if (hasPropertyKey(key, existingProperties)) {
Expand All @@ -426,7 +441,9 @@ export class ModelClassVisitor extends AbstractFileVisitor {
typeChecker,
existingProperties,
hostFilename,
options
options,
externalImports,
compilerOptionsPaths
);
return [factory.createPropertyAssignment(key, initializer)];
} else if (ts.isUnionTypeNode(node)) {
Expand All @@ -443,7 +460,9 @@ export class ModelClassVisitor extends AbstractFileVisitor {
typeChecker,
existingProperties,
hostFilename,
options
options,
externalImports,
compilerOptionsPaths
);
if (!isNullable) {
return propertyAssignments;
Expand Down Expand Up @@ -475,7 +494,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options,
factory,
type,
this._typeImports
this._typeImports,
compilerOptionsPaths
);

const initializer = factory.createArrowFunction(
Expand All @@ -495,7 +515,9 @@ export class ModelClassVisitor extends AbstractFileVisitor {
typeChecker: ts.TypeChecker,
existingProperties: ts.NodeArray<ts.PropertyAssignment>,
hostFilename: string,
options: PluginOptions
options: PluginOptions,
externalImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
) {
const propertyAssignments = Array.from(node.members || []).map((member) => {
const literalExpr = this.createDecoratorObjectLiteralExpr(
Expand All @@ -504,7 +526,10 @@ export class ModelClassVisitor extends AbstractFileVisitor {
typeChecker,
existingProperties,
options,
hostFilename
hostFilename,
undefined,
externalImports,
compilerOptionsPaths
);
return factory.createPropertyAssignment(
factory.createIdentifier(member.name.getText()),
Expand Down Expand Up @@ -544,7 +569,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
existingProperties: ts.NodeArray<ts.PropertyAssignment>,
hostFilename: string,
options: PluginOptions,
externalImports: Record<string, string>
externalImports: Record<string, string>,
compilerOptionsPaths: ts.MapLike<string[]>
) {
const key = 'enum';
if (hasPropertyKey(key, existingProperties)) {
Expand Down Expand Up @@ -592,7 +618,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options,
factory,
type,
this._typeImports
this._typeImports,
compilerOptionsPaths
);

const enumProperty = factory.createPropertyAssignment(key, enumIdentifier);
Expand Down
4 changes: 4 additions & 0 deletions test/plugin/fixtures/project/cats/dto/absolute-owner.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum AbsoluteOwner {
YES = 'YES',
NO = 'NO'
}
Loading

0 comments on commit d2eac71

Please sign in to comment.