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
4 changes: 2 additions & 2 deletions .hooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pnpm --filter jin-frame run build
echo -e "\n ${yellow}* code build end.${no_color}"

echo -e "\n ${yellow}* code test start.${no_color}"
pnpm --filter @jin-frame/generator-core run test
pnpm --filter jin-frame run test
pnpm --filter @jin-frame/generator-core run test:silent
pnpm --filter jin-frame run test:silent
echo -e "\n ${yellow}* code test end.${no_color}"

echo -e "\n ${green}* pre-commit hook was SUCCESSFUL${no_color} \n"
5 changes: 3 additions & 2 deletions packages/jin-frame/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jin-frame",
"version": "5.0.3",
"version": "5.0.4",
"description": "Reusable HTTP API request definition library",
"packageManager": "pnpm@10.16.0",
"scripts": {
Expand All @@ -20,9 +20,10 @@
"pub:prod": "pnpm run bundle && cross-env RELEASE_MODE=true pnpm publish --access=public",
"clean": "rimraf dist",
"lint": "eslint --cache .",
"lint:silent": "eslint --cache --quiet .",
"lint-staged": "lint-staged",
"test:only": "vitest run --coverage",
"test:silent": "vitest run --coverage",
"test:silent": "vitest run --coverage --silent",
"test": "vitest run --coverage",
"ctix": "ctix build --config .configs/.ctirc",
"ctix-rm": "ctix remove --force-yes --remove-backup",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getFieldMetadata } from '#decorators/fields/handlers/getFieldMetadata';
import { Param } from '#decorators/fields/Param';
import { Query } from '#decorators/fields/Query';
import { Post } from '#decorators/methods/Post';
import { Get } from '#decorators/methods/Get';
import { describe, expect, it } from 'vitest';
import { Body } from '#decorators/fields/Body';
import { ObjectBody } from '#decorators/fields/ObjectBody';
Expand Down Expand Up @@ -105,3 +106,70 @@ describe('getFieldMetadata', () => {
});
});
});

@Post({ host: 'https://api.somesite.com', path: 'base/path' })
class BaseRequest extends JinFrame {
@Query()
readonly baseField!: string;

@Header({ replaceAt: 'X-Base-Header' })
readonly baseHeader!: string;
}

@Get({ host: 'https://api.somesite.com', path: 'child/path' })
class ChildRequest extends BaseRequest {
@Param()
readonly childParam!: string;

@Body()
readonly childBody!: string;
}

@Post({ host: 'https://api.somesite.com', path: 'override/base' })
class OverrideBaseRequest extends JinFrame {
@Query()
readonly sharedField!: string;
}

@Get({ host: 'https://api.somesite.com', path: 'override/child' })
class OverrideChildRequest extends OverrideBaseRequest {
@Body()
declare readonly sharedField: string;
}

describe('getFieldMetadata with inheritance', () => {
it('should include parent class field metadata in child class', () => {
const r = ChildRequest.of({
baseField: 'base-value',
baseHeader: 'base-header-value',
childParam: 'child-param-value',
childBody: 'child-body-value',
});

const metas = getFieldMetadata(
r.constructor.prototype,
Object.entries(r).map(([key, value]) => ({ key, value })),
);

expect(metas.query).toEqual(expect.arrayContaining([expect.objectContaining({ key: 'baseField', type: 'query' })]));
expect(metas.header).toEqual(
expect.arrayContaining([expect.objectContaining({ key: 'baseHeader', replaceAt: 'X-Base-Header' })]),
);
expect(metas.param).toEqual(
expect.arrayContaining([expect.objectContaining({ key: 'childParam', type: 'param' })]),
);
expect(metas.body).toEqual(expect.arrayContaining([expect.objectContaining({ key: 'childBody', type: 'body' })]));
});

it('should use child decorator when child overrides a field from parent', () => {
const r = OverrideChildRequest.of({ sharedField: 'value' });

const metas = getFieldMetadata(
r.constructor.prototype,
Object.entries(r).map(([key, value]) => ({ key, value })),
);

expect(metas.body).toEqual(expect.arrayContaining([expect.objectContaining({ key: 'sharedField', type: 'body' })]));
expect(metas.query).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function getFieldMetadata(type: object, keys: { key: string; value: unkno
const fields: { key: string; meta: FieldEntry }[] = [];

for (const key of keys) {
const raw = Reflect.getOwnMetadata(REQUEST_FIELD_DECORATOR, type, key.key) as FieldEntry[] | undefined;
const raw = Reflect.getMetadata(REQUEST_FIELD_DECORATOR, type, key.key) as FieldEntry[] | undefined;

if (raw != null) {
for (const entry of raw) {
Expand Down
Loading