Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(plugin): support compiler options paths mapping #3134

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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