[1] 메소드 + 파라미터

import 'reflect-metadata';

// 데코레이터 심볼 정의
const parameterDecoratorSymbol = Symbol('parameterDecorator');

// 파라미터 데코레이터 함수 정의
function logParameter(target: any, key: string | symbol, index: number) {
    const existingParameterDecorators = Reflect.getMetadata(parameterDecoratorSymbol, target, key) || [];

    // 현재 파라미터에 데코레이터 적용 여부 저장
    Reflect.defineMetadata(parameterDecoratorSymbol, [...existingParameterDecorators, index], target, key);
}

// 데코레이터 함수 정의
function logMethod(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    // 파라미터 목록 가져오기
    const paramTypes = Reflect.getMetadata('design:paramtypes', target, key);
    
    // 데코레이터 적용 여부 가져오기
    const decoratedParameters = Reflect.getMetadata(parameterDecoratorSymbol, target, key) || [];

    // 새로운 메서드 정의
    descriptor.value = function (...args: any[]) {
        // 함수 호출 전 로깅
        console.log(`Calling method ${key} with arguments: ${JSON.stringify(args)}`);

        // 파라미터 목록 및 데코레이터 적용 여부 확인
        paramTypes.forEach((paramType, index) => {
            const isDecorated = decoratedParameters.includes(index);
            console.log(`Parameter ${index + 1} (${paramType.name})${isDecorated ? ' - Decorated' : ''}: ${args[index]}`);
        });

        // 원본 메서드 호출
        const result = originalMethod.apply(this, args);

        // 함수 호출 후 로깅
        console.log(`Method ${key} returned: ${JSON.stringify(result)}`);

        return result;
    };

    return descriptor;
}

// 클래스 정의
class ExampleClass {
    // 멤버 함수에 데코레이터 적용
    @logMethod
    public exampleMethod(@logParameter message: string, @logParameter numberValue: number): string {
        return `Received message: ${message}, Number: ${numberValue}`;
    }
}

// 인스턴스 생성
const instance = new ExampleClass();

// 데코레이터에 의해 메서드 호출 시 로그 출력
const result = instance.exampleMethod('Hello, Decorators!', 42);
console.log(result);