Skip to content

Commit

Permalink
Merge pull request #418 from Jujulego/feat/bind-decorator
Browse files Browse the repository at this point in the history
Add bind decorator
  • Loading branch information
Jujulego authored Oct 15, 2023
2 parents 371c943 + 3a80470 commit fb8108d
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 347 deletions.
6 changes: 5 additions & 1 deletion .swcrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"jsc": {
"target": "esnext",
"parser": {
"syntax": "typescript"
"syntax": "typescript",
"decorators": true
},
"transform": {
"decoratorVersion": "2022-03"
}
},
"module": {
Expand Down
6 changes: 0 additions & 6 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,4 @@ changesetBaseRefs:
- next
- origin/next

packageExtensions:
rollup-plugin-swc3@*:
peerDependenciesMeta:
rollup:
optional: true

yarnPath: .yarn/releases/yarn-3.6.3.cjs
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jujulego/aegis",
"version": "2.0.0-beta.5",
"version": "2.0.0-beta.6",
"license": "MIT",
"author": "Julien Capellari <julien.capellari@google.com>",
"repository": {
Expand Down Expand Up @@ -37,6 +37,7 @@
},
"devDependencies": {
"@jujulego/jill": "2.3.2",
"@jujulego/vite-plugin-swc": "1.1.0",
"@microsoft/eslint-formatter-sarif": "3.0.0",
"@swc/cli": "0.1.62",
"@swc/core": "1.3.87",
Expand All @@ -47,9 +48,10 @@
"eslint": "8.50.0",
"eslint-plugin-vitest": "0.3.1",
"jsdom": "22.1.0",
"rollup-plugin-swc3": "0.10.1",
"shx": "0.3.4",
"typescript": "5.2.2",
"vite": "5.0.0-beta.7",
"vite-tsconfig-paths": "4.2.1",
"vitest": "0.34.5"
},
"packageManager": "yarn@3.6.3",
Expand Down
23 changes: 23 additions & 0 deletions src/bind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { SyncMutableRef, SyncRef } from './defs/index.js';

// Types
export type BindDecorator<V> = <T>(target: ClassAccessorDecoratorTarget<T, V>, ctx: ClassAccessorDecoratorContext<T, V>) => ClassAccessorDecoratorResult<T, V>;

// Decorator
export function BindRef<V, D extends V>(ref: SyncRef<D> | SyncMutableRef<D>): BindDecorator<V> {
return (_, ctx) => {
const result: ClassAccessorDecoratorResult<unknown, D> = {
get: ref.read,
};

if ('mutate' in ref) {
result.set = ref.mutate;
} else {
result.set = () => {
throw new Error(`Cannot set ${String(ctx.name)}, it is bound to a readonly reference.`);
};
}

return result;
};
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './bind.js';
export * from './defs/index.js';
export * from './flow.js';
export * from './manager.js';
Expand Down
2 changes: 1 addition & 1 deletion src/refs/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { ref$ } from './ref.js';
import { SyncRef } from '../defs/index.js';

// Builder
export function const$<D>(value: D): SyncRef<D> {
export function const$<const D>(value: D): SyncRef<D> {
return ref$(() => value);
}
45 changes: 45 additions & 0 deletions tests/bind.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BindRef } from '@/src/bind.js';
import { const$ } from '@/src/refs/const.js';
import { var$ } from '@/src/refs/var.js';

// Tests
describe('bind$', () => {
it('should bind getter to ref read method', () => {
const value = const$(42);
vi.spyOn(value, 'read');

const life = new class {
@BindRef(value)
accessor value: 42;
};

expect(life.value).toBe(42);
expect(value.read).toHaveBeenCalledOnce();
});

it('should throw on attempt to set a accessor bound to a read only reference', () => {
const value = const$(42);
vi.spyOn(value, 'read');

const life = new class {
@BindRef(value)
accessor value: number;
};

expect(() => { life.value = 42; }).toThrow('Cannot set value, it is bound to a readonly reference');
});

it('should bind setter to ref mutate method', () => {
const value = var$(0);
vi.spyOn(value, 'mutate');

const life = new class {
@BindRef(value)
accessor value: number;
};

life.value = 42;

expect(value.mutate).toHaveBeenCalledWith(42);
});
});
22 changes: 4 additions & 18 deletions vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { swc } from 'rollup-plugin-swc3';
import { swc } from '@jujulego/vite-plugin-swc';
import tsconfigPaths from 'vite-tsconfig-paths';
import { defineConfig } from 'vitest/config';

export default defineConfig({
Expand All @@ -16,20 +15,7 @@ export default defineConfig({
}
},
plugins: [
swc({
jsc: {
target: 'esnext',
parser: {
syntax: 'typescript'
},
baseUrl: dirname(fileURLToPath(import.meta.url)),
paths: {
'@/src/*': ['./src/*']
}
},
module: {
type: 'es6'
}
})
tsconfigPaths(),
swc()
]
});
Loading

0 comments on commit fb8108d

Please sign in to comment.