feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
/*
* 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 { injectable, multiInject, optional } from 'inversify';
import { type StandardNodeType } from '@coze-workflow/base/types';
import {
EncapsulateNodeValidator,
type EncapsulateValidateManager,
EncapsulateNodesValidator,
EncapsulateWorkflowJSONValidator,
} from './types';
@injectable()
export class EncapsulateValidateManagerImpl
implements EncapsulateValidateManager
{
@multiInject(EncapsulateNodesValidator)
@optional()
private nodesValidators: EncapsulateNodesValidator[] = [];
@multiInject(EncapsulateNodeValidator)
@optional()
private nodeValidators: EncapsulateNodeValidator[] = [];
@multiInject(EncapsulateWorkflowJSONValidator)
@optional()
private workflowJSONValidators: EncapsulateWorkflowJSONValidator[] = [];
getNodeValidators() {
return this.nodeValidators || [];
}
getNodesValidators() {
return this.nodesValidators || [];
}
getWorkflowJSONValidators() {
return this.workflowJSONValidators || [];
}
getNodeValidatorsByType(type: StandardNodeType) {
return (this.nodeValidators || []).filter(validator =>
validator.canHandle(type),
);
}
dispose() {
this.nodeValidators = [];
this.nodesValidators = [];
this.workflowJSONValidators = [];
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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 { injectable } from 'inversify';
import {
type EncapsulateValidateResult,
type EncapsulateValidateErrorCode,
type EncapsulateValidateError,
} from './types';
@injectable()
export class EncapsulateValidateResultImpl
implements EncapsulateValidateResult
{
private errors: Map<string, EncapsulateValidateError[]> = new Map();
addError(error: EncapsulateValidateError) {
if (!this.errors.has(error.code)) {
this.errors.set(error.code, []);
}
const errors = this.errors.get(error.code);
if (errors && !errors.some(item => item.source === error.source)) {
errors.push(error);
}
}
getErrors() {
return [...this.errors.values()].flat();
}
hasError() {
return this.errors.size > 0;
}
hasErrorCode(code: EncapsulateValidateErrorCode) {
return this.errors.has(code);
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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 { inject, injectable } from 'inversify';
import { type StandardNodeType } from '@coze-workflow/base/types';
import {
type WorkflowJSON,
type WorkflowNodeEntity,
} from '@flowgram-adapter/free-layout-editor';
import { excludeStartEnd } from '../utils/exclude-start-end';
import { EncapsulateGenerateService } from '../generate';
import {
EncapsulateValidateManager,
type EncapsulateValidateService,
type EncapsulateValidateResult,
EncapsulateValidateResultFactory,
} from './types';
@injectable()
export class EncapsulateValidateServiceImpl
implements EncapsulateValidateService
{
@inject(EncapsulateValidateManager)
private encapsulateValidateManager: EncapsulateValidateManager;
@inject(EncapsulateValidateResultFactory)
private encapsulateValidateResultFactory: EncapsulateValidateResultFactory;
@inject(EncapsulateGenerateService)
private encapsulateGenerateService: EncapsulateGenerateService;
async validate(nodes: WorkflowNodeEntity[]) {
const validateResult: EncapsulateValidateResult =
this.encapsulateValidateResultFactory();
this.validateNodes(nodes, validateResult);
for (const node of nodes) {
await this.validateNode(node, validateResult);
}
if (validateResult.hasError()) {
return validateResult;
}
const workflowJSON =
await this.encapsulateGenerateService.generateWorkflowJSON(
excludeStartEnd(nodes),
);
await this.validateWorkflowJSON(workflowJSON, validateResult);
return validateResult;
}
private async validateWorkflowJSON(
workflowJSON: WorkflowJSON,
validateResult: EncapsulateValidateResult,
) {
const workflowJSONValidators =
this.encapsulateValidateManager.getWorkflowJSONValidators();
await Promise.all(
workflowJSONValidators.map(workflowJSONValidator =>
workflowJSONValidator.validate(workflowJSON, validateResult),
),
);
}
private validateNodes(
nodes: WorkflowNodeEntity[],
validateResult: EncapsulateValidateResult,
) {
const nodesValidators =
this.encapsulateValidateManager.getNodesValidators();
for (const nodesValidator of nodesValidators) {
// 如果节点校验器需要包含起始节点和结束节点,则直接校验
// 否则需要排除起始节点和结束节点
nodesValidator.validate(
nodesValidator.includeStartEnd ? nodes : excludeStartEnd(nodes),
validateResult,
);
}
}
private async validateNode(
node: WorkflowNodeEntity,
validateResult: EncapsulateValidateResult,
) {
const nodeValidators =
this.encapsulateValidateManager.getNodeValidatorsByType(
node.flowNodeType as StandardNodeType,
);
for (const nodeValidator of nodeValidators) {
await nodeValidator.validate(node, validateResult);
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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 './encapsulate-validate-manager';
export * from './types';
export * from './encapsulate-validate-service';
export * from './encapsulate-validate-result';

View File

@@ -0,0 +1,195 @@
/*
* 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 StandardNodeType } from '@coze-workflow/base/types';
import {
type WorkflowJSON,
type WorkflowNodeEntity,
} from '@flowgram-adapter/free-layout-editor';
/**
* 封装校验结果
*/
export interface EncapsulateValidateError {
/**
* 错误码
*/
code: EncapsulateValidateErrorCode;
/**
* 错误信息
*/
message: string;
/**
* 错误来源, 如果是节点问题, 就是节点ID
*/
source?: string;
/**
* 错误来源名称
*/
sourceName?: string;
/**
* 来源图标
*/
sourceIcon?: string;
}
/**
* 校验错误码
*/
export enum EncapsulateValidateErrorCode {
NO_START_END = '1001',
INVALID_PORTS = '1002',
ENCAPSULATE_LINES = '1003',
AT_LEAST_TWO_NODES = '1005',
INVALID_FORM = '1006',
VALIDATE_ERROR = '1007',
INVALID_SCHEMA = '1008',
INVALID_LOOP_NODES = '1009',
INVALID_SUB_CANVAS = '1010',
}
/**
* 校验结果
*/
export interface EncapsulateValidateResult {
/**
* 是否有错误
*/
hasError: () => boolean;
/**
* 添加错误
*/
addError: (error: EncapsulateValidateError) => void;
/**
* 获取错误列表
* @returns
*/
getErrors: () => EncapsulateValidateError[];
/**
* 是否有特定code的错误
*/
hasErrorCode: (code: EncapsulateValidateErrorCode) => boolean;
}
export const EncapsulateValidateResult = Symbol('EncapsulateValidateResult');
/**
* 校验结果工厂
*/
export type EncapsulateValidateResultFactory = () => EncapsulateValidateResult;
export const EncapsulateValidateResultFactory = Symbol(
'EncapsulateValidateResultFactory',
);
/**
* 封装节点校验器
*/
export interface EncapsulateNodeValidator {
/**
* 节点类型
*/
canHandle: (type: StandardNodeType) => boolean;
/**
* 节点校验
*/
validate: (
node: WorkflowNodeEntity,
result: EncapsulateValidateResult,
) => void | Promise<void>;
}
export const EncapsulateNodeValidator = Symbol('EncapsulateNodeValidator');
/**
* 所有节点级别的校验器
*/
export interface EncapsulateNodesValidator {
/**
* 所有节点校验
*/
validate: (
nodes: WorkflowNodeEntity[],
result: EncapsulateValidateResult,
) => void;
/**
* 是否包含开始和结束节点
*/
includeStartEnd?: boolean;
}
export const EncapsulateNodesValidator = Symbol('EncapsulateNodesValidator');
/**
* 流程JSON校验器
*/
export interface EncapsulateWorkflowJSONValidator {
validate: (
json: WorkflowJSON,
result: EncapsulateValidateResult,
) => void | Promise<void>;
}
export const EncapsulateWorkflowJSONValidator = Symbol(
'EncapsulateWorkflowJSONValidator',
);
/**
* 封装校验管理
*/
export interface EncapsulateValidateManager {
/**
* 获取所有节点校验器
*/
getNodeValidators: () => EncapsulateNodeValidator[];
/**
* 根据节点类型获取对应的校验器
* @param type
* @returns
*/
getNodeValidatorsByType: (
type: StandardNodeType,
) => EncapsulateNodeValidator[];
/**
* 获取所有流程级别校验器
*/
getNodesValidators: () => EncapsulateNodesValidator[];
/**
* 获取所有流程JSON校验器
* @returns
*/
getWorkflowJSONValidators: () => EncapsulateWorkflowJSONValidator[];
/**
* 销毁
*/
dispose: () => void;
}
export const EncapsulateValidateManager = Symbol('EncapsulateValidateManager');
/**
* 封装校验服务
*/
export interface EncapsulateValidateService {
/**
* 校验
* @param nodes
* @returns
*/
validate: (nodes: WorkflowNodeEntity[]) => Promise<EncapsulateValidateResult>;
}
export const EncapsulateValidateService = Symbol('EncapsulateValidateService');