feat(runtime-adapters): Enable TypeScript decorator support for Deno and Bun runtimes and add decorator tests
This commit is contained in:
13
bunfig.toml
Normal file
13
bunfig.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
# Bun configuration for tstest
|
||||
# This enables TypeScript decorator support in Bun runtime
|
||||
|
||||
[build]
|
||||
target = "bun"
|
||||
|
||||
[test]
|
||||
preload = []
|
||||
|
||||
# Enable decorators for Bun's TypeScript transpiler
|
||||
# This ensures user code with decorators works when executed via Bun
|
||||
[transpiler]
|
||||
experimentalDecorators = true
|
||||
@@ -1,5 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-11-17 - 2.8.0 - feat(runtime-adapters)
|
||||
Enable TypeScript decorator support for Deno and Bun runtimes and add decorator tests
|
||||
|
||||
- Add bunfig.toml to enable experimentalDecorators for Bun runtime
|
||||
- Add deno.json to enable experimentalDecorators and set target/lib for Deno
|
||||
- Update Bun runtime adapter to note bunfig.toml discovery so Bun runs with decorator support
|
||||
- Update Deno runtime adapter to auto-detect deno.json / deno.jsonc and pass configPath in default options
|
||||
- Add integration tests for decorators (test/decorator.all.ts) to verify decorator support across runtimes
|
||||
|
||||
## 2025-10-26 - 2.7.0 - feat(tapbundle_protocol)
|
||||
Add package export for tapbundle_protocol to expose protocol utilities
|
||||
|
||||
|
||||
8
deno.json
Normal file
8
deno.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"target": "ES2022"
|
||||
},
|
||||
"nodeModulesDir": true
|
||||
}
|
||||
91
test/decorator.all.ts
Normal file
91
test/decorator.all.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { tap, expect } from '../ts_tapbundle/index.js';
|
||||
|
||||
/**
|
||||
* Simple class decorator for testing decorator support across runtimes
|
||||
*/
|
||||
function testDecorator(target: any) {
|
||||
target.decoratorApplied = true;
|
||||
target.decoratorData = 'Decorator was applied successfully';
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method decorator for testing
|
||||
*/
|
||||
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||
const originalMethod = descriptor.value;
|
||||
descriptor.value = function (...args: any[]) {
|
||||
const result = originalMethod.apply(this, args);
|
||||
return `[logged] ${result}`;
|
||||
};
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter decorator for testing
|
||||
*/
|
||||
function validateParam(target: any, propertyKey: string, parameterIndex: number) {
|
||||
// Mark that parameter validation decorator was applied
|
||||
if (!target.decoratedParams) {
|
||||
target.decoratedParams = {};
|
||||
}
|
||||
if (!target.decoratedParams[propertyKey]) {
|
||||
target.decoratedParams[propertyKey] = [];
|
||||
}
|
||||
target.decoratedParams[propertyKey].push(parameterIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test class with decorators
|
||||
*/
|
||||
@testDecorator
|
||||
class TestClass {
|
||||
public name: string = 'test';
|
||||
|
||||
@logMethod
|
||||
public greet(message: string): string {
|
||||
return `Hello, ${message}!`;
|
||||
}
|
||||
|
||||
public getValue(): number {
|
||||
return 42;
|
||||
}
|
||||
|
||||
public testParams(@validateParam value: string): string {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Tests
|
||||
tap.test('Class decorator should be applied', async () => {
|
||||
expect((TestClass as any).decoratorApplied).toEqual(true);
|
||||
expect((TestClass as any).decoratorData).toEqual('Decorator was applied successfully');
|
||||
});
|
||||
|
||||
tap.test('Method decorator should modify method behavior', async () => {
|
||||
const instance = new TestClass();
|
||||
const result = instance.greet('World');
|
||||
expect(result).toEqual('[logged] Hello, World!');
|
||||
});
|
||||
|
||||
tap.test('Regular methods should work normally', async () => {
|
||||
const instance = new TestClass();
|
||||
expect(instance.getValue()).toEqual(42);
|
||||
expect(instance.name).toEqual('test');
|
||||
});
|
||||
|
||||
tap.test('Parameter decorator should be applied', async () => {
|
||||
const decoratedParams = (TestClass.prototype as any).decoratedParams;
|
||||
expect(decoratedParams).toBeDefined();
|
||||
expect(decoratedParams.testParams).toBeDefined();
|
||||
expect(decoratedParams.testParams).toContain(0);
|
||||
});
|
||||
|
||||
tap.test('Decorator metadata preservation', async () => {
|
||||
const instance = new TestClass();
|
||||
expect(instance instanceof TestClass).toEqual(true);
|
||||
expect(instance.constructor.name).toEqual('TestClass');
|
||||
expect(instance.testParams('hello')).toEqual('hello');
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@git.zone/tstest',
|
||||
version: '2.7.0',
|
||||
version: '2.8.0',
|
||||
description: 'a test utility to run tests that match test/**/*.ts'
|
||||
}
|
||||
|
||||
@@ -69,6 +69,9 @@ export class BunRuntimeAdapter extends RuntimeAdapter {
|
||||
|
||||
const args: string[] = ['run'];
|
||||
|
||||
// Note: Bun automatically discovers bunfig.toml in the current directory
|
||||
// This ensures TypeScript decorator support is enabled if bunfig.toml is present
|
||||
|
||||
// Add extra args
|
||||
if (mergedOptions.extraArgs && mergedOptions.extraArgs.length > 0) {
|
||||
args.push(...mergedOptions.extraArgs);
|
||||
|
||||
@@ -31,8 +31,20 @@ export class DenoRuntimeAdapter extends RuntimeAdapter {
|
||||
* Get default Deno options
|
||||
*/
|
||||
protected getDefaultOptions(): DenoOptions {
|
||||
// Auto-detect deno.json or deno.jsonc config file for TypeScript decorator support
|
||||
let configPath: string | undefined;
|
||||
const denoJsonPath = plugins.path.join(process.cwd(), 'deno.json');
|
||||
const denoJsoncPath = plugins.path.join(process.cwd(), 'deno.jsonc');
|
||||
|
||||
if (plugins.smartfile.fs.fileExistsSync(denoJsonPath)) {
|
||||
configPath = denoJsonPath;
|
||||
} else if (plugins.smartfile.fs.fileExistsSync(denoJsoncPath)) {
|
||||
configPath = denoJsoncPath;
|
||||
}
|
||||
|
||||
return {
|
||||
...super.getDefaultOptions(),
|
||||
configPath,
|
||||
permissions: [
|
||||
'--allow-read',
|
||||
'--allow-env',
|
||||
|
||||
Reference in New Issue
Block a user