From d77d5c775b6cde213e0ad8a2dbac0c269359ab9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20My=C5=9Bliwiec?= Date: Mon, 22 May 2023 13:55:18 +0200 Subject: [PATCH 1/2] chore: drop support for typescript < 4.8 --- lib/plugin/utils/plugin-utils.ts | 2 +- lib/plugin/visitors/abstract.visitor.ts | 81 +++++------------ .../visitors/controller-class.visitor.ts | 62 ++++--------- lib/plugin/visitors/model-class.visitor.ts | 86 ++++++------------- 4 files changed, 65 insertions(+), 166 deletions(-) diff --git a/lib/plugin/utils/plugin-utils.ts b/lib/plugin/utils/plugin-utils.ts index 793855d4c..9c10ac2b8 100644 --- a/lib/plugin/utils/plugin-utils.ts +++ b/lib/plugin/utils/plugin-utils.ts @@ -17,7 +17,7 @@ import { export function getDecoratorOrUndefinedByNames( names: string[], - decorators: ts.NodeArray, + decorators: readonly ts.Decorator[], factory: ts.NodeFactory ): ts.Decorator | undefined { return (decorators || factory.createNodeArray()).find((item) => { diff --git a/lib/plugin/visitors/abstract.visitor.ts b/lib/plugin/visitors/abstract.visitor.ts index 3f35ecd1f..c8ca2721c 100644 --- a/lib/plugin/visitors/abstract.visitor.ts +++ b/lib/plugin/visitors/abstract.visitor.ts @@ -9,71 +9,36 @@ export class AbstractFileVisitor { factory: ts.NodeFactory | undefined, program: ts.Program ): ts.SourceFile { - if (major <= 4 && minor < 2) { - throw new Error('Nest CLI plugin does not support TypeScript < v4.2'); + if (major <= 4 && minor < 8) { + throw new Error('Nest CLI plugin does not support TypeScript < v4.8'); } - const importEqualsDeclaration: ts.ImportDeclaration = - major >= 4 && minor >= 2 - ? minor >= 8 - ? (factory.createImportEqualsDeclaration as any)( - undefined, - false, - factory.createIdentifier(OPENAPI_NAMESPACE), - factory.createExternalModuleReference( - factory.createStringLiteral(OPENAPI_PACKAGE_NAME) - ) - ) - : (factory.createImportEqualsDeclaration as any)( - undefined, - undefined, - false, - OPENAPI_NAMESPACE, - factory.createExternalModuleReference( - factory.createStringLiteral(OPENAPI_PACKAGE_NAME) - ) - ) - : (factory.createImportEqualsDeclaration as any)( - undefined, - undefined, - OPENAPI_NAMESPACE, - factory.createExternalModuleReference( - factory.createStringLiteral(OPENAPI_PACKAGE_NAME) - ) - ); + const importEqualsDeclaration: ts.ImportEqualsDeclaration = + factory.createImportEqualsDeclaration( + undefined, + false, + factory.createIdentifier(OPENAPI_NAMESPACE), + factory.createExternalModuleReference( + factory.createStringLiteral(OPENAPI_PACKAGE_NAME) + ) + ); const compilerOptions = program.getCompilerOptions(); - // Support TS v4.8+ if ( compilerOptions.module >= ts.ModuleKind.ES2015 && compilerOptions.module <= ts.ModuleKind.ESNext ) { - const importAsDeclaration = - (minor >= 8 && major >= 4) || major >= 5 - ? (factory.createImportDeclaration as any)( - undefined, - factory.createImportClause( - false, - undefined, - factory.createNamespaceImport( - factory.createIdentifier(OPENAPI_NAMESPACE) - ) - ), - factory.createStringLiteral(OPENAPI_PACKAGE_NAME), - undefined - ) - : (factory.createImportDeclaration as any)( - undefined, - undefined, - factory.createImportClause( - false, - undefined, - factory.createNamespaceImport( - factory.createIdentifier(OPENAPI_NAMESPACE) - ) - ), - factory.createStringLiteral(OPENAPI_PACKAGE_NAME), - undefined - ); + const importAsDeclaration = (factory.createImportDeclaration as any)( + undefined, + factory.createImportClause( + false, + undefined, + factory.createNamespaceImport( + factory.createIdentifier(OPENAPI_NAMESPACE) + ) + ), + factory.createStringLiteral(OPENAPI_PACKAGE_NAME), + undefined + ); return factory.updateSourceFile(sourceFile, [ importAsDeclaration, ...sourceFile.statements diff --git a/lib/plugin/visitors/controller-class.visitor.ts b/lib/plugin/visitors/controller-class.visitor.ts index 48b146543..e71b1b511 100644 --- a/lib/plugin/visitors/controller-class.visitor.ts +++ b/lib/plugin/visitors/controller-class.visitor.ts @@ -18,11 +18,6 @@ import { } from '../utils/plugin-utils'; import { AbstractFileVisitor } from './abstract.visitor'; -const [tsVersionMajor, tsVersionMinor] = ts.versionMajorMinor - ?.split('.') - .map((x) => +x); -const isInUpdatedAstContext = tsVersionMinor >= 8 || tsVersionMajor > 4; - export class ControllerClassVisitor extends AbstractFileVisitor { visit( sourceFile: ts.SourceFile, @@ -61,10 +56,8 @@ export class ControllerClassVisitor extends AbstractFileVisitor { hostFilename: string, sourceFile: ts.SourceFile ): ts.MethodDeclaration { - // Support both >= v4.8 and v4.7 and lower - const decorators = (ts as any).canHaveDecorators - ? (ts as any).getDecorators(compilerNode) - : (compilerNode as any).decorators; + const decorators = + ts.canHaveDecorators(compilerNode) && ts.getDecorators(compilerNode); if (!decorators) { return compilerNode; } @@ -86,12 +79,7 @@ export class ControllerClassVisitor extends AbstractFileVisitor { ) : decorators; - // Support both >= v4.8 and v4.7 and lower - const modifiers = - (isInUpdatedAstContext - ? (ts as any).getModifiers(compilerNode) - : compilerNode.modifiers) ?? []; - + const modifiers = ts.getModifiers(compilerNode) ?? []; const updatedDecorators = [ ...apiOperationDecoratorsArray, ...existingDecorators, @@ -112,36 +100,23 @@ export class ControllerClassVisitor extends AbstractFileVisitor { ) ]; - return isInUpdatedAstContext - ? (factory as any).updateMethodDeclaration( - compilerNode, - [...updatedDecorators, ...modifiers], - compilerNode.asteriskToken, - compilerNode.name, - compilerNode.questionToken, - compilerNode.typeParameters, - compilerNode.parameters, - compilerNode.type, - compilerNode.body - ) - : (factory as any).updateMethodDeclaration( - compilerNode, - updatedDecorators, - modifiers, - compilerNode.asteriskToken, - compilerNode.name, - compilerNode.questionToken, - compilerNode.typeParameters, - compilerNode.parameters, - compilerNode.type, - compilerNode.body - ); + return factory.updateMethodDeclaration( + compilerNode, + [...updatedDecorators, ...modifiers], + compilerNode.asteriskToken, + compilerNode.name, + compilerNode.questionToken, + compilerNode.typeParameters, + compilerNode.parameters, + compilerNode.type, + compilerNode.body + ); } createApiOperationDecorator( factory: ts.NodeFactory, node: ts.MethodDeclaration, - nodeArray: ts.NodeArray, + decorators: readonly ts.Decorator[], options: PluginOptions, sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker @@ -152,7 +127,7 @@ export class ControllerClassVisitor extends AbstractFileVisitor { const keyToGenerate = options.controllerKeyOfComment; const apiOperationDecorator = getDecoratorOrUndefinedByNames( [ApiOperation.name], - nodeArray, + decorators, factory ); const apiOperationExpr: ts.ObjectLiteralExpression | undefined = @@ -279,10 +254,7 @@ export class ControllerClassVisitor extends AbstractFileVisitor { } getStatusCodeIdentifier(factory: ts.NodeFactory, node: ts.MethodDeclaration) { - // Support both >= v4.8 and v4.7 and lower - const decorators = (ts as any).canHaveDecorators - ? (ts as any).getDecorators(node) - : (node as any).decorators; + const decorators = ts.canHaveDecorators(node) && ts.getDecorators(node); const httpCodeDecorator = getDecoratorOrUndefinedByNames( ['HttpCode'], decorators, diff --git a/lib/plugin/visitors/model-class.visitor.ts b/lib/plugin/visitors/model-class.visitor.ts index 279ef8fac..d66d08079 100644 --- a/lib/plugin/visitors/model-class.visitor.ts +++ b/lib/plugin/visitors/model-class.visitor.ts @@ -1,6 +1,6 @@ import { compact, flatten, head } from 'lodash'; import * as ts from 'typescript'; -import { factory, PropertyAssignment } from 'typescript'; +import { PropertyAssignment, factory } from 'typescript'; import { ApiHideProperty } from '../../decorators'; import { PluginOptions } from '../merge-options'; import { METADATA_FACTORY_NAME } from '../plugin-constants'; @@ -27,11 +27,6 @@ import { AbstractFileVisitor } from './abstract.visitor'; type ClassMetadata = Record; -const [tsVersionMajor, tsVersionMinor] = ts.versionMajorMinor - ?.split('.') - .map((x) => +x); -const isInUpdatedAstContext = tsVersionMinor >= 8 || tsVersionMajor > 4; - export class ModelClassVisitor extends AbstractFileVisitor { visit( sourceFile: ts.SourceFile, @@ -46,10 +41,8 @@ export class ModelClassVisitor extends AbstractFileVisitor { (metadata: ClassMetadata) => (node: ts.Node): ts.Node => { if (ts.isPropertyDeclaration(node)) { - // Support both >= v4.8 and v4.7 and lower - const decorators = (ts as any).canHaveDecorators - ? (ts as any).getDecorators(node) - : (node as any).decorators; + const decorators = + ts.canHaveDecorators(node) && ts.getDecorators(node); const hidePropertyDecorator = getDecoratorOrUndefinedByNames( [ApiHideProperty.name], @@ -116,53 +109,25 @@ export class ModelClassVisitor extends AbstractFileVisitor { ) ) ); - const method = isInUpdatedAstContext - ? (factory as any).createMethodDeclaration( - [factory.createModifier(ts.SyntaxKind.StaticKeyword)], - undefined, - factory.createIdentifier(METADATA_FACTORY_NAME), - undefined, - undefined, - [], - undefined, - factory.createBlock( - [factory.createReturnStatement(returnValue)], - true - ) - ) - : (factory as any).createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.StaticKeyword)], - undefined, - factory.createIdentifier(METADATA_FACTORY_NAME), - undefined, - undefined, - [], - undefined, - factory.createBlock( - [factory.createReturnStatement(returnValue)], - true - ) - ); + const method = factory.createMethodDeclaration( + [factory.createModifier(ts.SyntaxKind.StaticKeyword)], + undefined, + factory.createIdentifier(METADATA_FACTORY_NAME), + undefined, + undefined, + [], + undefined, + factory.createBlock([factory.createReturnStatement(returnValue)], true) + ); - return isInUpdatedAstContext - ? (factory as any).updateClassDeclaration( - node, - node.modifiers, - node.name, - node.typeParameters, - node.heritageClauses, - [...node.members, method] - ) - : (factory as any).updateClassDeclaration( - node, - (node as any).decorators, - node.modifiers as any, - node.name, - node.typeParameters, - node.heritageClauses, - [...node.members, method] - ); + return factory.updateClassDeclaration( + node, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses, + [...node.members, method] + ); } inspectPropertyDeclaration( @@ -433,10 +398,7 @@ export class ModelClassVisitor extends AbstractFileVisitor { node: ts.PropertyDeclaration | ts.PropertySignature ): ts.PropertyAssignment[] { const assignments = []; - // Support both >= v4.8 and v4.7 and lower - const decorators = (ts as any).canHaveDecorators - ? (ts as any).getDecorators(node) - : (node as any).decorators; + const decorators = ts.canHaveDecorators(node) && ts.getDecorators(node); this.addPropertyByValidationDecorator( factory, @@ -549,7 +511,7 @@ export class ModelClassVisitor extends AbstractFileVisitor { factory: ts.NodeFactory, decoratorName: string, propertyKey: string, - decorators: ts.NodeArray, + decorators: readonly ts.Decorator[], assignments: ts.PropertyAssignment[] ) { this.addPropertiesByValidationDecorator( @@ -572,7 +534,7 @@ export class ModelClassVisitor extends AbstractFileVisitor { addPropertiesByValidationDecorator( factory: ts.NodeFactory, decoratorName: string, - decorators: ts.NodeArray, + decorators: readonly ts.Decorator[], assignments: ts.PropertyAssignment[], addPropertyAssignments: (decoratorRef: ts.Decorator) => PropertyAssignment[] ) { From 0693fbaa7de7d89d0b0b32d442b7a69f5932b361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20My=C5=9Bliwiec?= Date: Mon, 22 May 2023 14:01:47 +0200 Subject: [PATCH 2/2] chore: remove a ci job that runs tests for ts v4.8 --- .circleci/config.yml | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d677be46b..24c1aa928 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,27 +3,23 @@ version: 2 aliases: - &restore-cache restore_cache: - key: dependency-cache-{{ checksum "package.json" }} + key: dependency-cache-{{ checksum "package.json" }} - &install-deps run: - name: Install dependencies - command: npm ci + name: Install dependencies + command: npm ci - &build-packages run: - name: Build - command: npm run build + name: Build + command: npm run build - &run-unit-tests run: - name: Test - command: npm run test -- --runInBand - - &run-unit-tests - run: - name: Test (TypeScript < v4.8) - command: npm i --no-save -D typescript@4.7.2 && npm run test -- --runInBand + name: Test + command: npm run test -- --runInBand - &run-e2e-tests run: - name: E2E test - command: npm run test:e2e + name: E2E test + command: npm run test:e2e jobs: build: @@ -46,7 +42,7 @@ jobs: - ./node_modules - run: name: Build - command: npm run build + command: npm run build unit_tests: working_directory: ~/nest @@ -81,4 +77,3 @@ workflows: - e2e_tests: requires: - build -