chore: import upstream snapshot with attribution
CI / build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:09:51 +08:00
commit 0232b4e2bb
3528 changed files with 291404 additions and 0 deletions
@@ -0,0 +1,87 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { Container } from 'inversify';
import {
ASTFactory,
ScopeChain,
VariableContainerModule,
} from '@flowgram.ai/variable-core';
import { createPlaygroundContainer } from '@flowgram.ai/core';
import {
FreeLayoutScopeChain,
FixedLayoutScopeChain,
FlowNodeVariableData,
VariableChainConfig,
GlobalScope,
bindGlobalScope,
ScopeChainTransformService,
} from '../src';
import { EntityManager } from '@flowgram.ai/core';
import { VariableEngine } from '@flowgram.ai/variable-core';
import {
FlowDocument,
FlowDocumentContainerModule,
} from '@flowgram.ai/document';
import { WorkflowDocumentContainerModule } from '@flowgram.ai/free-layout-core';
export interface TestConfig extends VariableChainConfig {
enableGlobalScope?: boolean;
onInit?: (container: Container) => void;
runExtraTest?: (container: Container) => void
}
export function getContainer(layout: 'free' | 'fixed', config?: TestConfig): Container {
const { enableGlobalScope, onInit, runExtraTest, ...layoutConfig } = config || {};
const container = createPlaygroundContainer() as Container;
container.load(VariableContainerModule);
container.load(FlowDocumentContainerModule);
if (layout === 'free') {
container.load(WorkflowDocumentContainerModule);
// container.get(WorkflowLinesManager).registerContribution(WorkflowSimpleLineContribution);
//container.get(WorkflowLinesManager).switchLineType(WorkflowSimpleLineContribution.type);
}
if (layoutConfig) {
container.bind(VariableChainConfig).toConstantValue(layoutConfig);
}
if (layout === 'free') {
container.bind(ScopeChain).to(FreeLayoutScopeChain).inSingletonScope();
}
if (layout === 'fixed') {
container.bind(ScopeChain).to(FixedLayoutScopeChain).inSingletonScope();
}
container.bind(ScopeChainTransformService).toSelf().inSingletonScope();
bindGlobalScope(container.bind.bind(container))
const entityManager = container.get<EntityManager>(EntityManager);
const variableEngine = container.get<VariableEngine>(VariableEngine);
const document = container.get<FlowDocument>(FlowDocument);
if (enableGlobalScope) {
// when get global scope, it will auto create it if not exists
container.get(GlobalScope).setVar(ASTFactory.createVariableDeclaration({
key: 'GlobalScope',
type: ASTFactory.createString(),
}));
}
/**
* 扩展 FlowNodeVariableData
*/
entityManager.registerEntityData(
FlowNodeVariableData,
() => ({ variableEngine } as any),
);
document.registerNodeDatas(FlowNodeVariableData);
onInit?.(container);
return container;
}
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { FlowDocumentJSON } from '@flowgram.ai/document';
export const fixLayout1: FlowDocumentJSON = {
nodes: [
{
type: 'start',
meta: {
isStart: true,
},
id: 'start',
},
{
type: 'getRecords',
id: 'getRecords_07e97c55832',
},
{
type: 'loop',
id: 'forEach_260a8f85ff2',
blocks: [
{
type: 'createRecord',
id: 'createRecord_8f85ff2c11d',
},
{
type: 'dynamicSplit',
id: 'exclusiveSplit_ff2c11d0fb4',
blocks: [
{
id: 'branch_f2c11d0fb42',
},
{
id: 'branch_2c11d0fb42c',
},
],
},
],
},
{
type: 'dynamicSplit',
id: 'exclusiveSplit_88dbf2c60ae',
meta: {
defaultExpanded: true,
},
blocks: [
{
id: 'branch_8dbf2c60aee',
blocks: [
{
type: 'dynamicSplit',
id: 'exclusiveSplit_a59afaadc9a',
blocks: [
{
id: 'branch_59afaadc9ac',
},
{
id: 'branch_9afaadc9acd',
blocks: [
{
type: 'deleteRecords',
id: 'deleteRecords_c32807e97c5',
},
]
},
],
},
]
},
{
id: 'branch_dbf2c60aee4',
blocks: [
{
type: 'updateRecords',
id: 'updateRecords_7ed2a172c32',
},
]
},
],
},
{
type: 'end',
id: 'end',
},
],
};
@@ -0,0 +1,154 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { WorkflowJSON } from "@flowgram.ai/free-layout-core";
export const freeLayout1: WorkflowJSON = {
"nodes": [
{
"id": "start_0",
"type": "start",
"meta": {
"position": {
"x": -264,
"y": -79
}
},
"data": {}
},
{
"id": "end_0",
"type": "end",
"meta": {
"position": {
"x": 1515,
"y": -191
}
},
"data": {}
},
{
"id": "base_1",
"type": "base",
"meta": {
"position": {
"x": 103.5,
"y": -122.5
}
}
},
{
"id": "base_2",
"type": "base",
"meta": {
"position": {
"x": 525.5,
"y": -250.5
}
}
},
{
"id": "loop_1",
"type": "loop",
"meta": {
"position": {
"x": 541.5,
"y": 42.5
},
"canvasPosition": {
"x": 1154.5,
"y": 206.5
}
},
"data": {
"target": {
"meta": {
"name": "循环输出_"
},
"type": "Boolean"
}
},
"blocks": [
{
"id": "base_in_loop_1",
"type": "base",
"meta": {
"position": {
"x": 40,
"y": 100
}
}
},
{
"id": "base_in_loop_2",
"type": "base",
"meta": {
"position": {
"x": 62,
"y": 299
}
}
},
{
"id": "base_in_loop_3",
"type": "base",
"meta": {
"position": {
"x": 457,
"y": 188
}
}
}
],
"edges": [
{
"sourceNodeID": "base_in_loop_1",
"targetNodeID": "base_in_loop_3"
},
{
"sourceNodeID": "base_in_loop_2",
"targetNodeID": "base_in_loop_3"
}
]
},
{
"id": "base_3",
"type": "base",
"meta": {
"position": {
"x": 1063.5,
"y": -52.987060546875
}
}
}
],
"edges": [
{
"sourceNodeID": "base_2",
"targetNodeID": "end_0"
},
{
"sourceNodeID": "base_3",
"targetNodeID": "end_0"
},
{
"sourceNodeID": "start_0",
"targetNodeID": "base_1"
},
{
"sourceNodeID": "base_1",
"targetNodeID": "base_2"
},
{
"sourceNodeID": "base_1",
"targetNodeID": "loop_1"
},
{
"sourceNodeID": "loop_1",
"targetNodeID": "base_3",
"sourcePortID": "loop-output"
}
]
}
@@ -0,0 +1,108 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { describe, expect, test } from 'vitest';
import { VariableEngine } from '@flowgram.ai/variable-core';
import { ASTKind } from '@flowgram.ai/variable-core';
import { FlowDocument, FlowDocumentJSON } from '@flowgram.ai/document';
import {
FlowNodeVariableData,
} from '../src';
import { TestConfig, getContainer } from './container'
export const runFixedLayoutTest = (testName:string, spec: FlowDocumentJSON, config?: TestConfig) => {
describe(testName, () => {
const container = getContainer('fixed', config);
const flowDocument = container.get(FlowDocument);
const variableEngine = container.get(VariableEngine);
variableEngine.onScopeChange(action => {
const { type, scope } = action;
// 作用域默认创建一个默认变量
if (type === 'add') {
scope.ast.set('/', {
kind: ASTKind.VariableDeclaration,
type: ASTKind.String,
key: String(scope.id),
});
}
});
// 创建一个测试作用域
variableEngine.createScope('testScope');
const traverseVariableDatas = () =>
flowDocument
.getAllNodes()
// TODO 包含 $ 的节点不注册 variableData
.filter(_node => !_node.id.startsWith('$'))
.map(_node => _node.getData(FlowNodeVariableData))
.filter(Boolean);
// 初始化所有节点的私有作用域
const initAllNodePrivate = () => {
traverseVariableDatas().forEach(_data => {
_data.initPrivate();
});
};
// 初始化所有节点的可用变量
const printAllNodeAvailableMapping = (_scopeType: 'public' | 'private' = 'public') =>
traverseVariableDatas().reduce((acm, _data) => {
const scope = _data[_scopeType]!;
acm.set(String(scope.id), scope.available.variableKeys);
return acm;
}, new Map<string, string[]>());
// 初始化所有节点的覆盖作用域
const printAllCovers = (_scopeType: 'public' | 'private' = 'public') =>
traverseVariableDatas().reduce((acm, _data) => {
const scope = _data[_scopeType]!;
acm.set(
String(scope.id),
scope.coverScopes.map(_scope => String(_scope.id)),
);
return acm;
}, new Map<string, string[]>());
flowDocument.fromJSON(spec);
test('test get Deps', () => {
expect(printAllNodeAvailableMapping()).toMatchSnapshot();
});
test('test get Covers', () => {
expect(printAllCovers()).toMatchSnapshot();
});
test('test get Deps After Init Private', () => {
initAllNodePrivate();
expect(printAllNodeAvailableMapping()).toMatchSnapshot();
});
test('test get private scope Deps', () => {
expect(printAllNodeAvailableMapping('private')).toMatchSnapshot();
});
test('test get Covers After Init Private', () => {
expect(printAllCovers()).toMatchSnapshot();
});
test('test get private scope Covers', () => {
expect(printAllCovers('private')).toMatchSnapshot();
});
test('test sort', () => {
expect(variableEngine.getAllScopes({ sort: true }).map(_scope => _scope.id)).toMatchSnapshot();
});
config?.runExtraTest?.(container);
});
}
@@ -0,0 +1,108 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import { describe, expect, test } from 'vitest';
import { VariableEngine } from '@flowgram.ai/variable-core';
import { ASTKind } from '@flowgram.ai/variable-core';
import {
FlowNodeVariableData
} from '../src';
import { TestConfig, getContainer } from './container';
import { WorkflowDocument, WorkflowJSON } from '@flowgram.ai/free-layout-core';
export const runFreeLayoutTest = (testName: string, spec: WorkflowJSON, config?: TestConfig) => {
describe(testName, async () => {
const container = getContainer('free', config);
const flowDocument = container.get(WorkflowDocument);
const variableEngine = container.get(VariableEngine);
variableEngine.onScopeChange(action => {
const { type, scope } = action;
// 作用域默认创建一个默认变量
if (type === 'add') {
scope.ast.set('/', {
kind: ASTKind.VariableDeclaration,
type: ASTKind.String,
key: String(scope.id),
});
}
});
// 创建一个全局作用域
variableEngine.createScope('testScope');
const traverseVariableDatas = () =>
flowDocument
.getAllNodes()
// TODO 包含 $ 的节点不注册 variableData
.filter(_node => !_node.id.startsWith('$'))
.map(_node => _node.getData(FlowNodeVariableData))
.filter(Boolean);
// 初始化所有节点的私有作用域
const initAllNodePrivate = () => {
traverseVariableDatas().forEach(_data => {
_data.initPrivate();
});
};
// 初始化所有节点的可用变量
const printAllNodeAvailableMapping = (_scopeType: 'public' | 'private' = 'public') =>
traverseVariableDatas().reduce((acm, _data) => {
const scope = _data[_scopeType]!;
acm.set(String(scope.id), scope.available.variableKeys);
return acm;
}, new Map<string, string[]>());
// 初始化所有节点的覆盖作用域
const printAllCovers = (_scopeType: 'public' | 'private' = 'public') =>
traverseVariableDatas().reduce((acm, _data) => {
const scope = _data[_scopeType]!;
acm.set(
String(scope.id),
scope.coverScopes.map(_scope => String(_scope.id)),
);
return acm;
}, new Map<string, string[]>());
await flowDocument.fromJSON(spec);
test('test get Deps', () => {
expect(printAllNodeAvailableMapping()).toMatchSnapshot();
});
test('test get Covers', () => {
expect(printAllCovers()).toMatchSnapshot();
});
test('test get Deps After Init Private', () => {
initAllNodePrivate();
expect(printAllNodeAvailableMapping()).toMatchSnapshot();
});
test('test get private scope Deps', () => {
expect(printAllNodeAvailableMapping('private')).toMatchSnapshot();
});
test('test get Covers After Init Private', () => {
expect(printAllCovers()).toMatchSnapshot();
});
test('test get private scope Covers', () => {
expect(printAllCovers('private')).toMatchSnapshot();
});
test('test sort', () => {
expect(variableEngine.getAllScopes({ sort: true }).map(_scope => _scope.id)).toMatchSnapshot();
});
config?.runExtraTest?.(container);
});
}