feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
67
frontend/infra/idl/idl2ts-plugin/README.md
Normal file
67
frontend/infra/idl/idl2ts-plugin/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# @coze-arch/idl2ts-plugin
|
||||
|
||||
@coze-arch/idl2ts-plugin
|
||||
|
||||
## Overview
|
||||
|
||||
This package is part of the Coze Studio monorepo and provides architecture functionality. It includes hook.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installation
|
||||
|
||||
Add this package to your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@coze-arch/idl2ts-plugin": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
rush update
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```typescript
|
||||
import { /* exported functions/components */ } from '@coze-arch/idl2ts-plugin';
|
||||
|
||||
// Example usage
|
||||
// TODO: Add specific usage examples
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Hook
|
||||
|
||||
## API Reference
|
||||
|
||||
### Exports
|
||||
|
||||
- `*`
|
||||
- `*`
|
||||
|
||||
|
||||
For detailed API documentation, please refer to the TypeScript definitions.
|
||||
|
||||
## Development
|
||||
|
||||
This package is built with:
|
||||
|
||||
- TypeScript
|
||||
- Modern JavaScript
|
||||
- Vitest for testing
|
||||
- ESLint for code quality
|
||||
|
||||
## Contributing
|
||||
|
||||
This package is part of the Coze Studio monorepo. Please follow the monorepo contribution guidelines.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
131
frontend/infra/idl/idl2ts-plugin/__tests__/plugin.test.ts
Normal file
131
frontend/infra/idl/idl2ts-plugin/__tests__/plugin.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type Ctxs, type IPlugin, Program, on, before, after } from '../src';
|
||||
|
||||
interface Ctx {
|
||||
count: number;
|
||||
}
|
||||
interface Hook extends Ctxs {
|
||||
add: Ctx;
|
||||
reduce: Ctx;
|
||||
acc: { text: string };
|
||||
}
|
||||
|
||||
class AddPlugin implements IPlugin {
|
||||
apply(program: Program<Hook>): void {
|
||||
program.register(on('add'), ctx => {
|
||||
ctx.count += 1;
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
}
|
||||
class ReducePlugin implements IPlugin {
|
||||
apply(program: Program<Hook>): void {
|
||||
program.register(on('reduce'), ctx => {
|
||||
ctx.count -= 1;
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe('Program', () => {
|
||||
it('should apply plugin', () => {
|
||||
const program = Program.create<Hook>([new AddPlugin(), new ReducePlugin()]);
|
||||
expect(program.trigger('add', { count: 0 }).count).toEqual(1);
|
||||
expect(program.trigger('reduce', { count: 0 }).count).toEqual(-1);
|
||||
});
|
||||
it('should apply plugin by priority', () => {
|
||||
class FirstPlugin implements IPlugin {
|
||||
apply(program: Program<Hook>): void {
|
||||
program.register(
|
||||
on('reduce'),
|
||||
ctx => {
|
||||
ctx.count = 1;
|
||||
return ctx;
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
class SecondPlugin implements IPlugin {
|
||||
apply(program: Program<Hook>): void {
|
||||
program.register(
|
||||
on('reduce'),
|
||||
ctx => {
|
||||
ctx.count = 2;
|
||||
return ctx;
|
||||
},
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
const program = Program.create<Hook>([
|
||||
new SecondPlugin(),
|
||||
new FirstPlugin(),
|
||||
]);
|
||||
expect(program.trigger('reduce', { count: 0 }).count).toEqual(2);
|
||||
});
|
||||
it('should apply plugin by order: before -> on -> after', () => {
|
||||
class Plugin implements IPlugin {
|
||||
apply(program: Program<Hook>): void {
|
||||
program.register(before('acc'), ctx => {
|
||||
ctx.text += 'before';
|
||||
return ctx;
|
||||
});
|
||||
program.register(on('acc'), ctx => {
|
||||
ctx.text += '_on';
|
||||
return ctx;
|
||||
});
|
||||
program.register(after('acc'), ctx => {
|
||||
ctx.text += '_after';
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
}
|
||||
const program = Program.create<Hook>([new Plugin()]);
|
||||
expect(program.trigger('acc', { text: '' }).text).toEqual(
|
||||
'before_on_after',
|
||||
);
|
||||
});
|
||||
it('should load plugin be fine', () => {
|
||||
class Plugin implements IPlugin {
|
||||
apply(program: Program<Hook>): void {
|
||||
program.register(before('acc'), ctx => {
|
||||
ctx.text += 'before';
|
||||
return ctx;
|
||||
});
|
||||
program.register(on('acc'), ctx => {
|
||||
ctx.text += '_on';
|
||||
return ctx;
|
||||
});
|
||||
program.register(after('acc'), ctx => {
|
||||
ctx.text += '_after';
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
}
|
||||
const program = Program.create<Hook>([]);
|
||||
program.loadPlugins([new Plugin()]);
|
||||
expect(program.trigger('acc', { text: '' }).text).toEqual(
|
||||
'before_on_after',
|
||||
);
|
||||
});
|
||||
it('should throw error if has no register', () => {
|
||||
const program = Program.create<Hook>([]);
|
||||
expect(() => program.trigger('acc', { text: '' })).toThrowError();
|
||||
});
|
||||
});
|
||||
12
frontend/infra/idl/idl2ts-plugin/config/rush-project.json
Normal file
12
frontend/infra/idl/idl2ts-plugin/config/rush-project.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"operationSettings": [
|
||||
{
|
||||
"operationName": "test:cov",
|
||||
"outputFolderNames": ["coverage"]
|
||||
},
|
||||
{
|
||||
"operationName": "ts-check",
|
||||
"outputFolderNames": ["dist"]
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/infra/idl/idl2ts-plugin/eslint.config.js
Normal file
15
frontend/infra/idl/idl2ts-plugin/eslint.config.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const { defineConfig } = require('@coze-arch/eslint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
packageRoot: __dirname,
|
||||
preset: 'node',
|
||||
rules: {
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'unicorn/filename-case': 'off',
|
||||
'@coze-arch/no-batch-import-or-export': 'off',
|
||||
'max-statements-per-line': 'off',
|
||||
'max-lines': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@coze-arch/max-line-per-function': 'off',
|
||||
},
|
||||
});
|
||||
24
frontend/infra/idl/idl2ts-plugin/package.json
Normal file
24
frontend/infra/idl/idl2ts-plugin/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@coze-arch/idl2ts-plugin",
|
||||
"version": "0.1.6",
|
||||
"description": "@coze-arch/idl2ts-plugin",
|
||||
"license": "Apache-2.0",
|
||||
"author": "fanwenjie.fe@bytedance.com",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coze-arch/eslint-config": "workspace:*",
|
||||
"@coze-arch/ts-config": "workspace:*",
|
||||
"@coze-arch/vitest-config": "workspace:*",
|
||||
"@types/node": "^18",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"tsx": "^4.19.2",
|
||||
"vitest": "~3.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
35
frontend/infra/idl/idl2ts-plugin/src/hooks.ts
Normal file
35
frontend/infra/idl/idl2ts-plugin/src/hooks.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export enum Phases {
|
||||
BEFORE = 'BEFORE',
|
||||
ON = 'ON',
|
||||
AFTER = 'AFTER',
|
||||
}
|
||||
|
||||
export const phases = Object.values(Phases);
|
||||
|
||||
export const joinPhases = <T extends string>(phase: Phases, hook: T) =>
|
||||
`__${phase}__::${hook}`;
|
||||
|
||||
export const on = <T extends string>(hook: T) =>
|
||||
joinPhases(Phases.ON, hook) as `__ON__::${T}`;
|
||||
export const before = <T extends string>(hook: T) =>
|
||||
joinPhases(Phases.BEFORE, hook) as `__BEFORE__::${T}`;
|
||||
export const after = <T extends string>(hook: T) =>
|
||||
joinPhases(Phases.AFTER, hook) as `__AFTER__::${T}`;
|
||||
|
||||
export default Phases;
|
||||
18
frontend/infra/idl/idl2ts-plugin/src/index.ts
Normal file
18
frontend/infra/idl/idl2ts-plugin/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './hooks';
|
||||
export * from './program';
|
||||
123
frontend/infra/idl/idl2ts-plugin/src/program.ts
Normal file
123
frontend/infra/idl/idl2ts-plugin/src/program.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { joinPhases, Phases } from './hooks';
|
||||
|
||||
type IHookHandler<T> = (args: T) => T;
|
||||
|
||||
export interface Args {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface Ctxs {
|
||||
[key: string]: Args;
|
||||
}
|
||||
|
||||
export class Program<C extends Ctxs = any> {
|
||||
static create = <K extends Ctxs = any>(plugins: IPlugin[]) => {
|
||||
const p = new Program<K>();
|
||||
p.loadPlugins(plugins);
|
||||
return p;
|
||||
};
|
||||
|
||||
private hooks: string[] = [];
|
||||
|
||||
private phases = [Phases.BEFORE, Phases.ON, Phases.AFTER];
|
||||
|
||||
private handlers: {
|
||||
[event: string]: { handler: IHookHandler<any>; priority: number }[];
|
||||
} = {};
|
||||
|
||||
/**
|
||||
* 加载插件
|
||||
* @param plugins
|
||||
*/
|
||||
loadPlugins(plugins: IPlugin[]) {
|
||||
for (const plugin of plugins) {
|
||||
plugin.apply(this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 注册钩子
|
||||
* @param event 事件名称
|
||||
* @param handler 钩子
|
||||
* @param priority 优先级,数值越小,优先级越高
|
||||
*/
|
||||
register<
|
||||
K extends keyof C,
|
||||
P extends `__${'ON' | 'BEFORE' | 'AFTER'}__::${string & K}`,
|
||||
>(
|
||||
event: P,
|
||||
handler: IHookHandler<
|
||||
P extends `__${'ON' | 'BEFORE' | 'AFTER'}__::${infer R}`
|
||||
? C[R & keyof C]
|
||||
: never
|
||||
>,
|
||||
priority = 1,
|
||||
) {
|
||||
if (
|
||||
!this.hooks.find(h => this.phases.find(p => joinPhases(p, h) === event))
|
||||
) {
|
||||
const res = /__(ON|BEFORE|AFTER)__::(\S+)/.exec(event);
|
||||
if (!res || !res[2]) {
|
||||
throw new Error(
|
||||
`unknown hook must be one of ${JSON.stringify(this.hooks)}`,
|
||||
);
|
||||
}
|
||||
this.hooks.push(res[2]);
|
||||
}
|
||||
const handlers = this.handlers[event];
|
||||
if (handlers) {
|
||||
handlers.push({ handler, priority });
|
||||
} else {
|
||||
this.handlers[event] = [{ handler, priority }];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 触发事件
|
||||
* @param event
|
||||
* @param args
|
||||
* @returns
|
||||
*/
|
||||
trigger<T extends Args = Args>(event: keyof C, args: T): T {
|
||||
if (!this.hooks.find(i => event === i)) {
|
||||
throw new Error(
|
||||
`unknown hook must be one of ${JSON.stringify(this.hooks)}`,
|
||||
);
|
||||
}
|
||||
this.phases
|
||||
// @ts-expect-error fixme
|
||||
.map(i => joinPhases(i, event))
|
||||
.forEach(i => {
|
||||
args = this.applyEvent(i, args);
|
||||
});
|
||||
return args;
|
||||
}
|
||||
|
||||
private applyEvent<T extends Args = Args>(event: string, args: T) {
|
||||
const handler = this.handlers[event];
|
||||
if (handler) {
|
||||
for (const hook of handler.sort((a, b) => a.priority - b.priority)) {
|
||||
args = hook.handler.call(null, args);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPlugin<T extends Args = any> {
|
||||
apply: (program: Program<T>) => void;
|
||||
}
|
||||
25
frontend/infra/idl/idl2ts-plugin/tsconfig.build.json
Normal file
25
frontend/infra/idl/idl2ts-plugin/tsconfig.build.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.node.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"module": "CommonJS",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../config/eslint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/ts-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/vitest-config/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/infra/idl/idl2ts-plugin/tsconfig.json
Normal file
15
frontend/infra/idl/idl2ts-plugin/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"exclude": ["**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
frontend/infra/idl/idl2ts-plugin/tsconfig.misc.json
Normal file
19
frontend/infra/idl/idl2ts-plugin/tsconfig.misc.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.node.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
"module": "CommonJS",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"types": ["vitest/globals"]
|
||||
},
|
||||
"include": ["__tests__", "vitest.config.ts"],
|
||||
"exclude": ["./dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
frontend/infra/idl/idl2ts-plugin/vitest.config.ts
Normal file
22
frontend/infra/idl/idl2ts-plugin/vitest.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'node',
|
||||
});
|
||||
Reference in New Issue
Block a user