@flowgram.ai/form-materials 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/materials.ts +1 -0
- package/dist/esm/index.js +271 -11
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +81 -5
- package/dist/index.d.ts +81 -5
- package/dist/index.js +304 -49
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/components/assign-row/components/blur-input.tsx +27 -0
- package/src/components/assign-row/config.json +11 -0
- package/src/components/assign-row/index.tsx +84 -0
- package/src/components/assign-row/types.ts +25 -0
- package/src/components/assign-rows/config.json +11 -0
- package/src/components/assign-rows/index.tsx +59 -0
- package/src/components/constant-input/config.json +1 -1
- package/src/components/display-outputs/index.tsx +7 -1
- package/src/components/display-schema-tree/config.json +1 -1
- package/src/components/index.ts +2 -0
- package/src/components/variable-selector/index.tsx +1 -1
- package/src/effects/index.ts +1 -0
- package/src/effects/validate-when-variable-sync/config.json +5 -0
- package/src/effects/validate-when-variable-sync/index.ts +35 -0
- package/src/form-plugins/index.ts +1 -0
- package/src/form-plugins/infer-assign-plugin/config.json +7 -0
- package/src/form-plugins/infer-assign-plugin/index.ts +90 -0
- package/src/index.ts +1 -0
- package/src/plugins/json-schema-preset/create-type-preset-plugin.tsx +1 -1
- package/src/plugins/json-schema-preset/type-definition/array.tsx +2 -1
- package/src/plugins/json-schema-preset/type-definition/object.tsx +2 -1
- package/src/validate/index.tsx +6 -0
- package/src/validate/validate-flow-value/config.json +7 -0
- package/src/validate/validate-flow-value/index.tsx +73 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowgram.ai/form-materials",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"homepage": "https://flowgram.ai/",
|
|
5
5
|
"repository": "https://github.com/bytedance/flowgram.ai",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"@codemirror/view": "~6.38.0",
|
|
35
35
|
"@codemirror/state": "~6.5.2",
|
|
36
36
|
"typescript": "^5.8.3",
|
|
37
|
-
"@flowgram.ai/
|
|
38
|
-
"@flowgram.ai/
|
|
37
|
+
"@flowgram.ai/json-schema": "0.3.2",
|
|
38
|
+
"@flowgram.ai/editor": "0.3.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/lodash": "^4.14.137",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"tsup": "^8.0.1",
|
|
52
52
|
"typescript": "^5.8.3",
|
|
53
53
|
"vitest": "^0.34.6",
|
|
54
|
-
"@flowgram.ai/ts-config": "0.3.
|
|
55
|
-
"@flowgram.ai/eslint-config": "0.3.
|
|
54
|
+
"@flowgram.ai/ts-config": "0.3.2",
|
|
55
|
+
"@flowgram.ai/eslint-config": "0.3.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"react": ">=16.8",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useEffect, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import Input, { InputProps } from '@douyinfe/semi-ui/lib/es/input';
|
|
9
|
+
|
|
10
|
+
export function BlurInput(props: InputProps) {
|
|
11
|
+
const [value, setValue] = useState('');
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setValue(props.value as string);
|
|
15
|
+
}, [props.value]);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Input
|
|
19
|
+
{...props}
|
|
20
|
+
value={value}
|
|
21
|
+
onChange={(value) => {
|
|
22
|
+
setValue(value);
|
|
23
|
+
}}
|
|
24
|
+
onBlur={(e) => props.onChange?.(value, e)}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { IconButton } from '@douyinfe/semi-ui';
|
|
9
|
+
import { IconMinus } from '@douyinfe/semi-icons';
|
|
10
|
+
|
|
11
|
+
import { IFlowConstantRefValue } from '@/typings';
|
|
12
|
+
|
|
13
|
+
import { AssignRowProps } from './types';
|
|
14
|
+
import { BlurInput } from './components/blur-input';
|
|
15
|
+
import { VariableSelector } from '../variable-selector';
|
|
16
|
+
import { DynamicValueInput } from '../dynamic-value-input';
|
|
17
|
+
|
|
18
|
+
export function AssignRow(props: AssignRowProps) {
|
|
19
|
+
const {
|
|
20
|
+
value = {
|
|
21
|
+
operator: 'assign',
|
|
22
|
+
},
|
|
23
|
+
onChange,
|
|
24
|
+
onDelete,
|
|
25
|
+
readonly,
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
|
|
30
|
+
<div style={{ width: 150, minWidth: 150, maxWidth: 150 }}>
|
|
31
|
+
{value?.operator === 'assign' ? (
|
|
32
|
+
<VariableSelector
|
|
33
|
+
style={{ width: '100%', height: 26 }}
|
|
34
|
+
value={value?.left?.content}
|
|
35
|
+
config={{ placeholder: 'Select Left' }}
|
|
36
|
+
onChange={(v) =>
|
|
37
|
+
onChange?.({
|
|
38
|
+
...value,
|
|
39
|
+
left: { type: 'ref', content: v },
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
/>
|
|
43
|
+
) : (
|
|
44
|
+
<BlurInput
|
|
45
|
+
style={{ height: 26 }}
|
|
46
|
+
size="small"
|
|
47
|
+
placeholder="Input Name"
|
|
48
|
+
value={value?.left}
|
|
49
|
+
onChange={(v) =>
|
|
50
|
+
onChange?.({
|
|
51
|
+
...value,
|
|
52
|
+
left: v,
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
<div style={{ flexGrow: 1 }}>
|
|
59
|
+
<DynamicValueInput
|
|
60
|
+
readonly={readonly}
|
|
61
|
+
value={value?.right as IFlowConstantRefValue | undefined}
|
|
62
|
+
onChange={(v) =>
|
|
63
|
+
onChange?.({
|
|
64
|
+
...value,
|
|
65
|
+
right: v,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
{onDelete && (
|
|
71
|
+
<div>
|
|
72
|
+
<IconButton
|
|
73
|
+
size="small"
|
|
74
|
+
theme="borderless"
|
|
75
|
+
icon={<IconMinus />}
|
|
76
|
+
onClick={() => onDelete?.()}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { AssignValueType } from './types';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IFlowRefValue, IFlowValue } from '@/typings';
|
|
7
|
+
|
|
8
|
+
export type AssignValueType =
|
|
9
|
+
| {
|
|
10
|
+
operator: 'assign';
|
|
11
|
+
left?: IFlowRefValue;
|
|
12
|
+
right?: IFlowValue;
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
operator: 'declare';
|
|
16
|
+
left?: string;
|
|
17
|
+
right?: IFlowValue;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export interface AssignRowProps {
|
|
21
|
+
value?: AssignValueType;
|
|
22
|
+
onChange?: (value?: AssignValueType) => void;
|
|
23
|
+
onDelete?: () => void;
|
|
24
|
+
readonly?: boolean;
|
|
25
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { FieldArray, FieldArrayRenderProps } from '@flowgram.ai/editor';
|
|
9
|
+
import { Button } from '@douyinfe/semi-ui';
|
|
10
|
+
import { IconPlus } from '@douyinfe/semi-icons';
|
|
11
|
+
|
|
12
|
+
import { AssignRow, AssignValueType } from '../assign-row';
|
|
13
|
+
|
|
14
|
+
interface AssignRowsProps {
|
|
15
|
+
name: string;
|
|
16
|
+
readonly?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function AssignRows(props: AssignRowsProps) {
|
|
20
|
+
const { name, readonly } = props;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<FieldArray name={name}>
|
|
24
|
+
{({ field }: FieldArrayRenderProps<AssignValueType | undefined>) => (
|
|
25
|
+
<>
|
|
26
|
+
{field.map((childField, index) => (
|
|
27
|
+
<AssignRow
|
|
28
|
+
key={childField.key}
|
|
29
|
+
readonly={readonly}
|
|
30
|
+
value={childField.value}
|
|
31
|
+
onChange={(value) => {
|
|
32
|
+
childField.onChange(value);
|
|
33
|
+
}}
|
|
34
|
+
onDelete={() => field.remove(index)}
|
|
35
|
+
/>
|
|
36
|
+
))}
|
|
37
|
+
<div style={{ display: 'flex', gap: 5 }}>
|
|
38
|
+
<Button
|
|
39
|
+
size="small"
|
|
40
|
+
theme="borderless"
|
|
41
|
+
icon={<IconPlus />}
|
|
42
|
+
onClick={() => field.append({ operator: 'assign' })}
|
|
43
|
+
>
|
|
44
|
+
Assign
|
|
45
|
+
</Button>
|
|
46
|
+
<Button
|
|
47
|
+
size="small"
|
|
48
|
+
theme="borderless"
|
|
49
|
+
icon={<IconPlus />}
|
|
50
|
+
onClick={() => field.append({ operator: 'declare' })}
|
|
51
|
+
>
|
|
52
|
+
Declaration
|
|
53
|
+
</Button>
|
|
54
|
+
</div>
|
|
55
|
+
</>
|
|
56
|
+
)}
|
|
57
|
+
</FieldArray>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -51,7 +51,13 @@ export function DisplayOutputs({ value, showIconInTree, displayFromScope }: Prop
|
|
|
51
51
|
return (
|
|
52
52
|
<DisplayOutputsWrapper>
|
|
53
53
|
{childEntries.map(([key, schema]) => (
|
|
54
|
-
<DisplaySchemaTag
|
|
54
|
+
<DisplaySchemaTag
|
|
55
|
+
key={key}
|
|
56
|
+
title={key}
|
|
57
|
+
value={schema}
|
|
58
|
+
showIconInTree={showIconInTree}
|
|
59
|
+
warning={!schema}
|
|
60
|
+
/>
|
|
55
61
|
))}
|
|
56
62
|
</DisplayOutputsWrapper>
|
|
57
63
|
);
|
package/src/components/index.ts
CHANGED
|
@@ -130,7 +130,7 @@ export const VariableSelector = ({
|
|
|
130
130
|
showClear={false}
|
|
131
131
|
arrowIcon={<IconChevronDownStroked size="small" />}
|
|
132
132
|
triggerRender={triggerRender}
|
|
133
|
-
placeholder={config?.placeholder ?? 'Select Variable
|
|
133
|
+
placeholder={config?.placeholder ?? 'Select Variable'}
|
|
134
134
|
/>
|
|
135
135
|
</>
|
|
136
136
|
);
|
package/src/effects/index.ts
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { isEmpty } from 'lodash';
|
|
7
|
+
import {
|
|
8
|
+
DataEvent,
|
|
9
|
+
Effect,
|
|
10
|
+
EffectOptions,
|
|
11
|
+
getNodeScope,
|
|
12
|
+
getNodePrivateScope,
|
|
13
|
+
} from '@flowgram.ai/editor';
|
|
14
|
+
|
|
15
|
+
export const validateWhenVariableSync = ({
|
|
16
|
+
scope,
|
|
17
|
+
}: {
|
|
18
|
+
scope?: 'private' | 'public';
|
|
19
|
+
} = {}): EffectOptions[] => [
|
|
20
|
+
{
|
|
21
|
+
event: DataEvent.onValueInit,
|
|
22
|
+
effect: (({ context, form }) => {
|
|
23
|
+
const nodeScope =
|
|
24
|
+
scope === 'private' ? getNodePrivateScope(context.node) : getNodeScope(context.node);
|
|
25
|
+
|
|
26
|
+
const disposable = nodeScope.available.onListOrAnyVarChange(() => {
|
|
27
|
+
if (!isEmpty(form.state.errors)) {
|
|
28
|
+
form.validate();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return () => disposable.dispose();
|
|
33
|
+
}) as Effect,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { set, uniqBy } from 'lodash';
|
|
7
|
+
import { JsonSchemaUtils } from '@flowgram.ai/json-schema';
|
|
8
|
+
import {
|
|
9
|
+
ASTFactory,
|
|
10
|
+
createEffectFromVariableProvider,
|
|
11
|
+
defineFormPluginCreator,
|
|
12
|
+
FlowNodeRegistry,
|
|
13
|
+
getNodeForm,
|
|
14
|
+
getNodeScope,
|
|
15
|
+
} from '@flowgram.ai/editor';
|
|
16
|
+
|
|
17
|
+
import { IFlowRefValue, IFlowValue } from '../../typings';
|
|
18
|
+
|
|
19
|
+
type AssignValueType =
|
|
20
|
+
| {
|
|
21
|
+
operator: 'assign';
|
|
22
|
+
left?: IFlowRefValue;
|
|
23
|
+
right?: IFlowValue;
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
operator: 'declare';
|
|
27
|
+
left?: string;
|
|
28
|
+
right?: IFlowValue;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
interface InputConfig {
|
|
32
|
+
assignKey: string;
|
|
33
|
+
outputKey: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const createInferAssignPlugin = defineFormPluginCreator<InputConfig>({
|
|
37
|
+
onSetupFormMeta({ addFormatOnSubmit, mergeEffect }, { assignKey, outputKey }) {
|
|
38
|
+
if (!assignKey || !outputKey) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
mergeEffect({
|
|
43
|
+
[assignKey]: createEffectFromVariableProvider({
|
|
44
|
+
parse: (value: AssignValueType[], ctx) => {
|
|
45
|
+
const declareRows = uniqBy(
|
|
46
|
+
value.filter((_v) => _v.operator === 'declare' && _v.left && _v.right),
|
|
47
|
+
'left'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return [
|
|
51
|
+
ASTFactory.createVariableDeclaration({
|
|
52
|
+
key: `${ctx.node.id}`,
|
|
53
|
+
meta: {
|
|
54
|
+
title: getNodeForm(ctx.node)?.getValueIn('title'),
|
|
55
|
+
icon: ctx.node.getNodeRegistry<FlowNodeRegistry>().info?.icon,
|
|
56
|
+
},
|
|
57
|
+
type: ASTFactory.createObject({
|
|
58
|
+
properties: declareRows.map((_v) =>
|
|
59
|
+
ASTFactory.createProperty({
|
|
60
|
+
key: _v.left as string,
|
|
61
|
+
type:
|
|
62
|
+
_v.right?.type === 'constant'
|
|
63
|
+
? JsonSchemaUtils.schemaToAST(_v.right?.schema || {})
|
|
64
|
+
: undefined,
|
|
65
|
+
initializer:
|
|
66
|
+
_v.right?.type === 'ref'
|
|
67
|
+
? ASTFactory.createKeyPathExpression({
|
|
68
|
+
keyPath: _v.right?.content || [],
|
|
69
|
+
})
|
|
70
|
+
: {},
|
|
71
|
+
})
|
|
72
|
+
),
|
|
73
|
+
}),
|
|
74
|
+
}),
|
|
75
|
+
];
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
addFormatOnSubmit((formData, ctx) => {
|
|
81
|
+
set(
|
|
82
|
+
formData,
|
|
83
|
+
outputKey,
|
|
84
|
+
JsonSchemaUtils.astToSchema(getNodeScope(ctx.node).output.variables?.[0]?.type)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return formData;
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { jsonSchemaTypePreset } from './type-definition';
|
|
|
14
14
|
import { JsonSchemaTypeRegistry } from './manager';
|
|
15
15
|
|
|
16
16
|
export const createTypePresetPlugin = definePluginCreator<{
|
|
17
|
-
types?: JsonSchemaTypeRegistry[];
|
|
17
|
+
types?: Partial<JsonSchemaTypeRegistry> & Pick<JsonSchemaTypeRegistry, 'type'>[];
|
|
18
18
|
unregisterTypes?: string[];
|
|
19
19
|
}>({
|
|
20
20
|
onInit(ctx, opts) {
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
/* eslint-disable react/prop-types */
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
|
+
import { CodeEditorMini } from '@/components/code-editor-mini';
|
|
10
|
+
|
|
9
11
|
import { type JsonSchemaTypeRegistry } from '../manager';
|
|
10
|
-
import { CodeEditorMini } from '../../../components/code-editor-mini';
|
|
11
12
|
|
|
12
13
|
export const arrayRegistry: Partial<JsonSchemaTypeRegistry> = {
|
|
13
14
|
type: 'array',
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
/* eslint-disable react/prop-types */
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
|
+
import { CodeEditorMini } from '@/components/code-editor-mini';
|
|
10
|
+
|
|
9
11
|
import { type JsonSchemaTypeRegistry } from '../manager';
|
|
10
|
-
import { CodeEditorMini } from '../../../components/code-editor-mini';
|
|
11
12
|
|
|
12
13
|
export const objectRegistry: Partial<JsonSchemaTypeRegistry> = {
|
|
13
14
|
type: 'object',
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { isNil, uniq } from 'lodash';
|
|
7
|
+
import { FeedbackLevel, FlowNodeEntity, getNodeScope } from '@flowgram.ai/editor';
|
|
8
|
+
|
|
9
|
+
import { IFlowTemplateValue, IFlowValue } from '@/typings';
|
|
10
|
+
|
|
11
|
+
interface Context {
|
|
12
|
+
node: FlowNodeEntity;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
errorMessages?: {
|
|
15
|
+
required?: string;
|
|
16
|
+
unknownVariable?: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function validateFlowValue(value: IFlowValue | undefined, ctx: Context) {
|
|
21
|
+
const { node, required, errorMessages } = ctx;
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
required: requiredMessage = 'Field is required',
|
|
25
|
+
unknownVariable: unknownVariableMessage = 'Unknown Variable',
|
|
26
|
+
} = errorMessages || {};
|
|
27
|
+
|
|
28
|
+
if (required && (isNil(value) || isNil(value?.content) || value?.content === '')) {
|
|
29
|
+
return {
|
|
30
|
+
level: FeedbackLevel.Error,
|
|
31
|
+
message: requiredMessage,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (value?.type === 'ref') {
|
|
36
|
+
const variable = getNodeScope(node).available.getByKeyPath(value?.content || []);
|
|
37
|
+
if (!variable) {
|
|
38
|
+
return {
|
|
39
|
+
level: FeedbackLevel.Error,
|
|
40
|
+
message: unknownVariableMessage,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (value?.type === 'template') {
|
|
46
|
+
const allRefs = getTemplateKeyPaths(value);
|
|
47
|
+
|
|
48
|
+
for (const ref of allRefs) {
|
|
49
|
+
const variable = getNodeScope(node).available.getByKeyPath(ref);
|
|
50
|
+
if (!variable) {
|
|
51
|
+
return {
|
|
52
|
+
level: FeedbackLevel.Error,
|
|
53
|
+
message: unknownVariableMessage,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* get template key paths
|
|
64
|
+
* @param value
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
function getTemplateKeyPaths(value: IFlowTemplateValue) {
|
|
68
|
+
// find all keyPath wrapped in {{}}
|
|
69
|
+
const keyPathReg = /{{(.*?)}}/g;
|
|
70
|
+
return uniq(value.content?.match(keyPathReg) || []).map((_keyPath) =>
|
|
71
|
+
_keyPath.slice(2, -2).split('.')
|
|
72
|
+
);
|
|
73
|
+
}
|