Skip to content
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
2 changes: 2 additions & 0 deletions lib/plugin/merge-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface PluginOptions {
dtoKeyOfComment?: string;
controllerKeyOfComment?: string;
introspectComments?: boolean;
esmCompatible?: boolean;
readonly?: boolean;
pathToSource?: string;
debug?: boolean;
Expand All @@ -27,6 +28,7 @@ const defaultOptions: PluginOptions = {
dtoKeyOfComment: 'description',
controllerKeyOfComment: 'summary',
introspectComments: false,
esmCompatible: false,
readonly: false,
debug: false
};
Expand Down
23 changes: 23 additions & 0 deletions lib/plugin/utils/plugin-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@ export function hasPropertyKey(
.some((item) => item.name.getText() === key);
}

export function getOutputExtension(fileName: string): string {
if (fileName.endsWith('.mts')) {
return '.mjs';
} else if (fileName.endsWith('.cts')) {
return '.cjs';
} else {
return '.js';
}
}

export function replaceImportPath(
typeReference: string,
fileName: string,
Expand All @@ -148,6 +158,14 @@ export function replaceImportPath(
if (!typeReference.includes('import')) {
return { typeReference, importPath: null };
}

if (options.esmCompatible) {
typeReference = typeReference.replace(
', { with: { "resolution-mode": "import" } }',
''
);
}

let importPath = /\(\"([^)]).+(\")/.exec(typeReference)[0];
if (!importPath) {
return { typeReference: undefined, importPath: null };
Expand Down Expand Up @@ -193,6 +211,10 @@ export function replaceImportPath(
if (indexPos >= 0) {
relativePath = relativePath.slice(0, indexPos);
}
} else if (options.esmCompatible) {
// Add appropriate extension for non-node_modules imports
const extension = getOutputExtension(fileName);
relativePath += extension;
}

typeReference = typeReference.replace(importPath, relativePath);
Expand All @@ -206,6 +228,7 @@ export function replaceImportPath(
importPath: relativePath
};
}

return {
typeReference: typeReference.replace('import', 'require'),
importPath: relativePath
Expand Down
10 changes: 6 additions & 4 deletions lib/plugin/visitors/controller-class.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import {
convertPath,
getDecoratorOrUndefinedByNames,
getOutputExtension,
getTypeReferenceAsString,
hasPropertyKey
} from '../utils/plugin-utils';
Expand All @@ -34,13 +35,14 @@ export class ControllerClassVisitor extends AbstractFileVisitor {
return this._typeImports;
}

get collectedMetadata(): Array<
[ts.CallExpression, Record<string, ClassMetadata>]
> {
collectedMetadata(
options: PluginOptions
): Array<[ts.CallExpression, Record<string, ClassMetadata>]> {
const metadataWithImports = [];
Object.keys(this._collectedMetadata).forEach((filePath) => {
const metadata = this._collectedMetadata[filePath];
const path = filePath.replace(/\.[jt]s$/, '');
const fileExt = options.esmCompatible ? getOutputExtension(filePath) : '';
const path = filePath.replace(/\.[jt]s$/, fileExt);
const importExpr = ts.factory.createCallExpression(
ts.factory.createToken(ts.SyntaxKind.ImportKeyword) as ts.Expression,
undefined,
Expand Down
10 changes: 6 additions & 4 deletions lib/plugin/visitors/model-class.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
convertPath,
extractTypeArgumentIfArray,
getDecoratorOrUndefinedByNames,
getOutputExtension,
getTypeReferenceAsString,
hasPropertyKey,
isAutoGeneratedEnumUnion,
Expand All @@ -43,13 +44,14 @@ export class ModelClassVisitor extends AbstractFileVisitor {
return this._typeImports;
}

get collectedMetadata(): Array<
[ts.CallExpression, Record<string, ClassMetadata>]
> {
collectedMetadata(
options: PluginOptions
): Array<[ts.CallExpression, Record<string, ClassMetadata>]> {
const metadataWithImports = [];
Object.keys(this._collectedMetadata).forEach((filePath) => {
const metadata = this._collectedMetadata[filePath];
const path = filePath.replace(/\.[jt]s$/, '');
const fileExt = options.esmCompatible ? getOutputExtension(filePath) : '';
const path = filePath.replace(/\.[jt]s$/, fileExt);
const importExpr = ts.factory.createCallExpression(
ts.factory.createToken(ts.SyntaxKind.ImportKeyword) as ts.Expression,
undefined,
Expand Down
4 changes: 2 additions & 2 deletions lib/plugin/visitors/readonly.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export class ReadonlyVisitor {

collect() {
return {
models: this.modelClassVisitor.collectedMetadata,
controllers: this.controllerClassVisitor.collectedMetadata
models: this.modelClassVisitor.collectedMetadata(this.options),
controllers: this.controllerClassVisitor.collectedMetadata(this.options)
};
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"author": "Kamil Mysliwiec",
"license": "MIT",
"repository": "https://github.com/nestjs/swagger",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.build.json",
"format": "prettier \"lib/**/*.ts\" --write",
Expand All @@ -13,6 +15,7 @@
"publish:next": "npm publish --access public --tag next",
"prepublish:npm": "npm run build",
"publish:npm": "npm publish --access public",
"prepare": "npm run build",
"test": "jest",
"test:dev": "jest --watch",
"test:e2e": "jest --config e2e/jest-e2e.json",
Expand Down
2 changes: 2 additions & 0 deletions test/plugin/fixtures/create-option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const mergedCliPluginMultiOption = {
dtoKeyOfComment: 'description',
controllerKeyOfComment: 'summary',
introspectComments: true,
esmCompatible: false,
readonly: false,
debug: false
};
Expand All @@ -28,6 +29,7 @@ export const mergedCliPluginSingleOption = {
dtoKeyOfComment: 'description',
controllerKeyOfComment: 'summary',
introspectComments: true,
esmCompatible: false,
readonly: false,
debug: false
};
23 changes: 16 additions & 7 deletions test/plugin/fixtures/parameter-property.dto.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getOutputExtension } from '../../../lib/plugin/utils/plugin-utils';

export const parameterPropertyDtoText = `
export class ParameterPropertyDto {
constructor(
readonly readonlyValue?: string,
private privateValue: string | null,
public publicValue: ItemDto[],
readonly readonlyValue?: string,
private privateValue: string | null,
public publicValue: ItemDto[],
regularParameter: string
protected protectedValue: string = '1234',
protected protectedValue: string = '1234',
) {}
}

Expand All @@ -20,7 +22,13 @@ export class ItemDto {
}
`;

export const parameterPropertyDtoTextTranspiled = `import * as openapi from "@nestjs/swagger";
export const parameterPropertyDtoTextTranspiled = (esmCompatible?: boolean) => {
let fileName = 'parameter-property.dto';
if (esmCompatible) {
fileName += getOutputExtension(fileName);
}

return `import * as openapi from "@nestjs/swagger";
export class ParameterPropertyDto {
constructor(readonlyValue, privateValue, publicValue, regularParameter, protectedValue = '1234') {
this.readonlyValue = readonlyValue;
Expand All @@ -29,7 +37,7 @@ export class ParameterPropertyDto {
this.protectedValue = protectedValue;
}
static _OPENAPI_METADATA_FACTORY() {
return { readonlyValue: { required: false, type: () => String }, privateValue: { required: true, type: () => String, nullable: true }, publicValue: { required: true, type: () => [require("./parameter-property.dto").ItemDto] }, protectedValue: { required: true, type: () => String, default: "1234" } };
return { readonlyValue: { required: false, type: () => String }, privateValue: { required: true, type: () => String, nullable: true }, publicValue: { required: true, type: () => [require("./${fileName}").ItemDto] }, protectedValue: { required: true, type: () => String, default: "1234" } };
}
}
export var LettersEnum;
Expand All @@ -43,7 +51,8 @@ export class ItemDto {
this.enumValue = enumValue;
}
static _OPENAPI_METADATA_FACTORY() {
return { enumValue: { required: true, enum: require("./parameter-property.dto").LettersEnum } };
return { enumValue: { required: true, enum: require("./${fileName}").LettersEnum } };
}
}
`;
};
Loading