feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const ROOT_DIR = process.cwd();
|
||||
|
||||
// 工具函数 aa-bb-cc -> AaBbCc
|
||||
const getPascalName = name =>
|
||||
name
|
||||
.split('-')
|
||||
.map(s => s.slice(0, 1).toUpperCase() + s.slice(1))
|
||||
.join('');
|
||||
|
||||
// 工具函数 aa-bb-cc -> aaBbCc
|
||||
const getCamelName = name =>
|
||||
name
|
||||
.split('-')
|
||||
.map((s, i) => (i === 0 ? s : s.slice(0, 1).toUpperCase() + s.slice(1)))
|
||||
.join('');
|
||||
|
||||
// 工具函数 aa-bb-cc -> AA_BB_CC
|
||||
const getConstantName = name =>
|
||||
name
|
||||
.split('-')
|
||||
.map(s => s.toUpperCase())
|
||||
.join('_');
|
||||
|
||||
module.exports = plop => {
|
||||
// 注册一个新的动作,用于在导出文件和注册文件中添加新的节点注册信息
|
||||
plop.setActionType('registryNode', async answers => {
|
||||
const { name, pascalName, supportTest } = answers;
|
||||
const constantName = getConstantName(name);
|
||||
const registryName = `${constantName}_NODE_REGISTRY`;
|
||||
|
||||
// 修改导出文件
|
||||
const nodeExportFilePath = './src/node-registries/index.ts';
|
||||
const nodeContent = fs.readFileSync(nodeExportFilePath, 'utf8');
|
||||
const nodeContentNew = nodeContent.replace(
|
||||
'// cli 脚本插入标识(registry),请勿修改/删除此行注释',
|
||||
`export { ${registryName} } from './${name}';
|
||||
// cli 脚本插入标识(registry),请勿修改/删除此行注释`,
|
||||
);
|
||||
fs.writeFileSync(nodeExportFilePath, nodeContentNew, 'utf8');
|
||||
|
||||
// 修改注册文件
|
||||
const nodeRegistryFilePath = './src/nodes-v2/constants.ts';
|
||||
const nodeRegistryContent = fs.readFileSync(nodeRegistryFilePath, 'utf8');
|
||||
const nodeRegistryContentNew = nodeRegistryContent
|
||||
.replace(
|
||||
'// cli 脚本插入标识(import),请勿修改/删除此行注释',
|
||||
`${registryName},
|
||||
// cli 脚本插入标识(import),请勿修改/删除此行注释`,
|
||||
)
|
||||
.replace(
|
||||
'// cli 脚本插入标识(registry),请勿修改/删除此行注释',
|
||||
`// cli 脚本插入标识(registry),请勿修改/删除此行注释
|
||||
${registryName},`,
|
||||
);
|
||||
fs.writeFileSync(nodeRegistryFilePath, nodeRegistryContentNew, 'utf8');
|
||||
|
||||
// 修改 node-content 注册文件
|
||||
const nodeContentRegistryFilePath =
|
||||
'./src/components/node-render/node-render-new/content/index.tsx';
|
||||
const nodeContentRegistryContent = fs.readFileSync(
|
||||
nodeContentRegistryFilePath,
|
||||
'utf8',
|
||||
);
|
||||
|
||||
const nodeContentRegistryContentNew = nodeContentRegistryContent
|
||||
.replace(
|
||||
'// cli 脚本插入标识(import),请勿修改/删除此行注释',
|
||||
`import { ${pascalName}Content } from '@/node-registries/${name}';
|
||||
// cli 脚本插入标识(import),请勿修改/删除此行注释`,
|
||||
)
|
||||
.replace(
|
||||
'// cli 脚本插入标识(registry),请勿修改/删除此行注释',
|
||||
`[StandardNodeType.${pascalName}]: ${pascalName}Content,
|
||||
// cli 脚本插入标识(registry),请勿修改/删除此行注释`,
|
||||
);
|
||||
fs.writeFileSync(
|
||||
nodeContentRegistryFilePath,
|
||||
nodeContentRegistryContentNew,
|
||||
'utf8',
|
||||
);
|
||||
|
||||
// 如果节点无需支持单节点测试,删除 node-test 文件
|
||||
const testFilePath = path.resolve(
|
||||
ROOT_DIR,
|
||||
`./src/node-registries/${name}/node-test.ts`,
|
||||
);
|
||||
if (!supportTest && fs.existsSync(testFilePath)) {
|
||||
fs.unlinkSync(testFilePath);
|
||||
}
|
||||
|
||||
return `节点 ${name} 已注册`;
|
||||
});
|
||||
|
||||
// 注册一个新的生成器,用于创建新的节点目录和文件
|
||||
plop.setGenerator('create node', {
|
||||
description: 'generate template',
|
||||
prompts: [
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message:
|
||||
'请输入组件名称,以"-"(空格)分隔,用于生成目录名称, eg: "database-create"',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'pascalName',
|
||||
message:
|
||||
'请确认大写驼峰命名,用于类名,注意特殊命名: http -> HTTP ,而不是 http -> Http: ',
|
||||
default: answers => getPascalName(answers.name),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'camelName',
|
||||
message:
|
||||
'请确认小写驼峰命名,用于变量前缀,注意特殊命名: my-ai -> myAI,而不是 my-ai -> myAi: ',
|
||||
default: answers => getCamelName(answers.name),
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'supportTest',
|
||||
message: '是否支持单节点测试?',
|
||||
default: false,
|
||||
},
|
||||
],
|
||||
actions: data => {
|
||||
const { name, pascalName, camelName, supportTest } = data;
|
||||
const constantName = getConstantName(data.name);
|
||||
const actions = [
|
||||
{
|
||||
type: 'addMany',
|
||||
destination: path.resolve(ROOT_DIR, `./src/node-registries/${name}`),
|
||||
templateFiles: 'templates',
|
||||
data: {
|
||||
PASCAL_NAME_PLACE_HOLDER: pascalName,
|
||||
CAMEL_NAME_PLACE_HOLDER: camelName,
|
||||
CONSTANT_NAME_PLACE_HOLDER: constantName,
|
||||
SUPPORT_TEST: supportTest,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'registryNode',
|
||||
},
|
||||
];
|
||||
return actions;
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { nanoid } from 'nanoid';
|
||||
import { ViewVariableType } from '@coze-workflow/variable';
|
||||
|
||||
// 入参路径,试运行等功能依赖该路径提取参数
|
||||
export const INPUT_PATH = 'inputs.inputParameters';
|
||||
|
||||
// 定义固定出参
|
||||
export const OUTPUTS = [
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'outputList',
|
||||
type: ViewVariableType.ArrayObject,
|
||||
children: [
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'id',
|
||||
type: ViewVariableType.String,
|
||||
},
|
||||
{
|
||||
key: nanoid(),
|
||||
name: 'content',
|
||||
type: ViewVariableType.String,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,20 @@
|
||||
import { type NodeDataDTO } from '@coze-workflow/base';
|
||||
|
||||
import { type FormData } from './types';
|
||||
import { OUTPUTS } from './constants';
|
||||
|
||||
/**
|
||||
* 节点后端数据 -> 前端表单数据
|
||||
*/
|
||||
export const transformOnInit = (value: NodeDataDTO) => ({
|
||||
...(value ?? {}),
|
||||
outputs: value?.outputs ?? OUTPUTS,
|
||||
});
|
||||
|
||||
/**
|
||||
* 前端表单数据 -> 节点后端数据
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
export const transformOnSubmit = (value: FormData): NodeDataDTO =>
|
||||
value as unknown as NodeDataDTO;
|
||||
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
ValidateTrigger,
|
||||
type FormMetaV2,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { createValueExpressionInputValidate } from '@/node-registries/common/validators';
|
||||
import {
|
||||
fireNodeTitleChange,
|
||||
provideNodeOutputVariablesEffect,
|
||||
} from '@/node-registries/common/effects';
|
||||
|
||||
import { type FormData } from './types';
|
||||
import { FormRender } from './form';
|
||||
import { transformOnInit, transformOnSubmit } from './data-transformer';
|
||||
|
||||
export const {{CONSTANT_NAME_PLACE_HOLDER}}_FORM_META: FormMetaV2<FormData> = {
|
||||
// 节点表单渲染
|
||||
render: () => <FormRender />,
|
||||
|
||||
// 验证触发时机
|
||||
validateTrigger: ValidateTrigger.onChange,
|
||||
|
||||
// 验证规则
|
||||
validate: {
|
||||
// 必填
|
||||
'inputs.inputParameters.0.input': createValueExpressionInputValidate({
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
|
||||
// 副作用管理
|
||||
effect: {
|
||||
nodeMeta: fireNodeTitleChange,
|
||||
outputs: provideNodeOutputVariablesEffect,
|
||||
},
|
||||
|
||||
// 节点后端数据 -> 前端表单数据
|
||||
formatOnInit: transformOnInit,
|
||||
|
||||
// 前端表单数据 -> 节点后端数据
|
||||
formatOnSubmit: transformOnSubmit,
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { NodeConfigForm } from '@/node-registries/common/components';
|
||||
|
||||
import { OutputsField, InputsParametersField } from '../common/fields';
|
||||
import { INPUT_PATH } from './constants';
|
||||
|
||||
export const FormRender = () => (
|
||||
<NodeConfigForm>
|
||||
<InputsParametersField
|
||||
name={INPUT_PATH}
|
||||
title={I18n.t('node_http_request_params')}
|
||||
tooltip={I18n.t('node_http_request_params_desc')}
|
||||
defaultValue={[]}
|
||||
/>
|
||||
|
||||
<OutputsField
|
||||
title={I18n.t('workflow_detail_node_output')}
|
||||
tooltip={I18n.t('node_http_response_data')}
|
||||
id="{{CAMEL_NAME_PLACE_HOLDER}}-node-outputs"
|
||||
name="outputs"
|
||||
topLevelReadonly={true}
|
||||
customReadonly
|
||||
/>
|
||||
</NodeConfigForm>
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
export { {{CONSTANT_NAME_PLACE_HOLDER}}_NODE_REGISTRY } from './node-registry';
|
||||
export { {{PASCAL_NAME_PLACE_HOLDER}}Content } from './node-content';
|
||||
@@ -0,0 +1,10 @@
|
||||
import { InputParameters, Outputs } from '../common/components';
|
||||
|
||||
export function {{PASCAL_NAME_PLACE_HOLDER}}Content() {
|
||||
return (
|
||||
<>
|
||||
<InputParameters />
|
||||
<Outputs />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
DEFAULT_NODE_META_PATH,
|
||||
DEFAULT_OUTPUTS_PATH,
|
||||
} from '@coze-workflow/nodes';
|
||||
import {
|
||||
StandardNodeType,
|
||||
type WorkflowNodeRegistry,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
import { {{CONSTANT_NAME_PLACE_HOLDER}}_FORM_META } from './form-meta';
|
||||
import { INPUT_PATH } from './constants';
|
||||
{{#if SUPPORT_TEST}}
|
||||
import { test, type NodeTestMeta } from './node-test';
|
||||
{{/if}}
|
||||
|
||||
export const {{CONSTANT_NAME_PLACE_HOLDER}}_NODE_REGISTRY: WorkflowNodeRegistry{{#if SUPPORT_TEST}}<NodeTestMeta>{{/if}} = {
|
||||
type: StandardNodeType.{{PASCAL_NAME_PLACE_HOLDER}},
|
||||
meta: {
|
||||
nodeDTOType: StandardNodeType.{{PASCAL_NAME_PLACE_HOLDER}},
|
||||
size: { width: 360, height: 130.7 },
|
||||
nodeMetaPath: DEFAULT_NODE_META_PATH,
|
||||
outputsPath: DEFAULT_OUTPUTS_PATH,
|
||||
inputParametersPath: INPUT_PATH,
|
||||
test{{#unless SUPPORT_TEST}}: false{{/unless}},
|
||||
},
|
||||
formMeta: {{CONSTANT_NAME_PLACE_HOLDER}}_FORM_META,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { NodeTestMeta } from '@/test-run-kit';
|
||||
|
||||
const test: NodeTestMeta = true;
|
||||
|
||||
export { test, type NodeTestMeta };
|
||||
@@ -0,0 +1,5 @@
|
||||
import { type InputValueVO } from '@coze-workflow/base';
|
||||
|
||||
export interface FormData {
|
||||
inputs: { inputParameters: InputValueVO[] };
|
||||
}
|
||||
Reference in New Issue
Block a user