chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

@@ -31,7 +31,7 @@ interface ExpressionEditorCounterProps {
}
/**
* 长度计数器
* length counter
*/
export const ExpressionEditorCounter: FC<
ExpressionEditorCounterProps

View File

@@ -36,7 +36,7 @@ interface ExpressionEditorRenderProps {
}
/**
* 应当只包含编辑器逻辑,业务无关
* It should only contain editor logic, business-independent
*/
export const ExpressionEditorRender: React.FC<
ExpressionEditorRenderProps
@@ -57,7 +57,7 @@ export const ExpressionEditorRender: React.FC<
editor={model.editor}
initialValue={model.lines}
onChange={value => {
// eslint-disable-next-line @typescript-eslint/require-await -- 防止阻塞 slate 渲染
// eslint-disable-next-line @typescript-eslint/require-await -- prevent blocking slate rendering
const asyncOnChange = async () => {
const lines = value as ExpressionEditorLine[];
model.change(lines);

View File

@@ -45,9 +45,9 @@ import {
import styles from './index.module.less';
/** 内置函数 */
/** built-in function */
namespace SuggestionViewUtils {
/** 编辑器选中事件处理 */
/** Editor selected event handling */
export const editorSelectHandler = (params: {
reducer: SuggestionReducer;
payload: ExpressionEditorEventParams<ExpressionEditorEvent.Select>;
@@ -55,7 +55,7 @@ namespace SuggestionViewUtils {
const { reducer, payload } = params;
const [state, dispatch] = reducer;
// 设置解析数据
// Set up parse data
const parseData = ExpressionEditorParser.parse({
lineContent: payload.content,
lineOffset: payload.offset,
@@ -83,7 +83,7 @@ namespace SuggestionViewUtils {
},
});
// 重置UI组件内部状态
// Reset UI component internal state
const shouldRefresh = parseData.content.reachable === '';
if (shouldRefresh) {
dispatch({
@@ -91,7 +91,7 @@ namespace SuggestionViewUtils {
});
}
// 设置选中值
// Set the selected value
const selected = SuggestionViewUtils.computeSelected({
model: state.model,
parseData,
@@ -101,7 +101,7 @@ namespace SuggestionViewUtils {
payload: selected,
});
// 设置可见变量树
// Set the visible variable tree
const variableTree = SuggestionViewUtils.computeVariableTree({
model: state.model,
parseData,
@@ -111,7 +111,7 @@ namespace SuggestionViewUtils {
payload: variableTree,
});
// 设置匹配树枝
// Set matching branches
const matchTreeBranch: ExpressionEditorTreeNode[] | undefined =
ExpressionEditorTreeHelper.matchTreeBranch({
tree: state.model.variableTree,
@@ -122,7 +122,7 @@ namespace SuggestionViewUtils {
payload: matchTreeBranch,
});
// 设置空内容
// Set empty content
const emptyContent = SuggestionViewUtils.computeEmptyContent({
parseData,
fullVariableTree: state.model.variableTree,
@@ -134,7 +134,7 @@ namespace SuggestionViewUtils {
payload: emptyContent,
});
// 设置UI相对坐标
// Set UI relative coordinates
const rect = SuggestionViewUtils.computeRect(state);
dispatch({
type: SuggestionActionType.SetRect,
@@ -147,9 +147,9 @@ namespace SuggestionViewUtils {
return;
}
// FIXME: 设置搜索值很hack的逻辑后面建议重构不用semi组件自己写一个
// FIXME: Set the search value, very hacked logic. Later, it is recommended to refactor without semi components, and write one yourself.
if (!state.ref.tree.current) {
// 不设为可见获取不到ref
// Not set to visible can't get ref
dispatch({
type: SuggestionActionType.SetVisible,
payload: true,
@@ -168,7 +168,7 @@ namespace SuggestionViewUtils {
return 1;
};
/** 计算可见时相对父容器坐标 */
/** Calculate relative parent container coordinates when visible */
export const computeRect = (
state: SuggestionState,
):
@@ -194,12 +194,12 @@ namespace SuggestionViewUtils {
left: (rect.left - containerRect.left) / getFinalScale(state),
};
} catch (e) {
// slate DOM 计算报错可忽略
// Slate DOM calculation error can be ignored
return;
}
};
/** 计算当前选中变量 */
/** Calculate the currently selected variable */
export const computeSelected = (params: {
model: ExpressionEditorModel;
parseData: ExpressionEditorParseData;
@@ -218,7 +218,7 @@ namespace SuggestionViewUtils {
return treeBrach[treeBrach.length - 1];
};
/** 计算当前搜索值 */
/** Calculate the current search value */
export const computeSearch = (
parseData: ExpressionEditorParseData,
): string => {
@@ -229,7 +229,7 @@ namespace SuggestionViewUtils {
const lastSegment =
segments[segments.length - 1].type ===
ExpressionEditorSegmentType.ArrayIndex
? segments[segments.length - 2] // 数组索引属于上一层级,需要去除防止影响到搜索值
? segments[segments.length - 2] // The array index belongs to the previous level and needs to be removed to prevent it from affecting the search value
: segments[segments.length - 1];
if (
!lastSegment ||
@@ -240,7 +240,7 @@ namespace SuggestionViewUtils {
return lastSegment.objectKey;
};
/** 计算裁剪层级的变量树 */
/** Calculate the variable tree of the clipping level */
export const computeVariableTree = (params: {
model: ExpressionEditorModel;
parseData: ExpressionEditorParseData;
@@ -293,7 +293,7 @@ namespace SuggestionViewUtils {
export const keyboardSelectedClassName = () =>
styles['expression-editor-suggestion-keyboard-selected'];
/** 将选中项设为高亮 */
/** Highlight the selected item */
export const setUIOptionSelected = (uiOption: Element): void => {
if (
!uiOption?.classList?.add ||
@@ -305,7 +305,7 @@ namespace SuggestionViewUtils {
uiOption.classList.add(SuggestionViewUtils.keyboardSelectedClassName());
};
/** 获取所有选项UI元素 */
/** Get all options UI elements */
export const computeUIOptions = (
state: SuggestionState,
):
@@ -315,14 +315,14 @@ namespace SuggestionViewUtils {
selectedOption?: Element;
}
| undefined => {
// 获取所有的选项元素
// Get all option elements
const optionListDom =
state.ref.suggestion.current?.children?.[0]?.children?.[1]?.children;
if (!optionListDom) {
return;
}
const optionList = Array.from(optionListDom);
// 找到当前高亮的选项
// Find the currently highlighted option
const selectedIndex = optionList.findIndex(element =>
element.classList.contains(keyboardSelectedClassName()),
);
@@ -333,7 +333,7 @@ namespace SuggestionViewUtils {
};
};
/** 禁止变更 visible 防止 ui 抖动 */
/** Disable visible changes Prevent UI jitter */
export const preventVisibleJitter = (
reducer: SuggestionReducer,
time = 150,
@@ -354,18 +354,18 @@ namespace SuggestionViewUtils {
}, time);
};
/** 清空键盘UI选项 */
/** Clear keyboard UI options */
export const clearSelectedUIOption = (state: SuggestionState) => {
const uiOptions = SuggestionViewUtils.computeUIOptions(state);
if (uiOptions?.selectedOption) {
// 清空键盘选中状态
// Clear keyboard selection
uiOptions.selectedOption.classList.remove(
SuggestionViewUtils.keyboardSelectedClassName(),
);
}
};
/** 默认键盘UI选项为第一项 */
/** The default keyboard UI option is the first item */
export const selectFirstUIOption = (state: SuggestionState) => {
const uiOptions = SuggestionViewUtils.computeUIOptions(state);
if (!uiOptions?.optionList) {
@@ -375,12 +375,12 @@ namespace SuggestionViewUtils {
if (!uiOptions?.optionList?.[0]?.classList?.add) {
return;
}
// 默认首项高亮
// Default first item highlighting
SuggestionViewUtils.setUIOptionSelected(uiOptions.optionList[0]);
};
}
/** 选中节点 */
/** selected node */
export const useSelectNode = (reducer: SuggestionReducer) => {
const [state] = reducer;
return useCallback(
@@ -403,7 +403,7 @@ export const useSelectNode = (reducer: SuggestionReducer) => {
},
};
const insertText = `${ExpressionEditorToken.FullStart}${fullPath}${ExpressionEditorToken.FullEnd}`;
// 替换文本
// replacement text
Transforms.insertText(state.model.editor, insertText, {
at: selection,
});
@@ -412,12 +412,12 @@ export const useSelectNode = (reducer: SuggestionReducer) => {
);
};
/** 挂载监听器 */
/** mount the listener */
export const useListeners = (reducer: SuggestionReducer) => {
const [state, dispatch] = reducer;
useEffect(() => {
// 挂载监听: 鼠标点击事件
// Mount Listening: Mouse Click Events
const mouseHandler = (e: MouseEvent) => {
if (!state.visible || !state.ref.suggestion.current) {
return;
@@ -439,13 +439,13 @@ export const useListeners = (reducer: SuggestionReducer) => {
window.removeEventListener('mousedown', mouseHandler);
};
return () => {
// 销毁时卸载监听器防止内存泄露
// Prevent memory leaks by uninstalling listeners when destroyed
mouseDisposer();
};
}, [state]);
useEffect(() => {
// 挂载监听: 编辑器选择事件
// Mount Listening: Editor Selection Event
const editorSelectDisposer = state.model.on<ExpressionEditorEvent.Select>(
ExpressionEditorEvent.Select,
payload =>
@@ -455,13 +455,13 @@ export const useListeners = (reducer: SuggestionReducer) => {
}),
);
return () => {
// 销毁时卸载监听器防止内存泄露
// Prevent memory leaks by uninstalling listeners when destroyed
editorSelectDisposer();
};
}, []);
useEffect(() => {
// 挂载监听: 编辑器拼音输入事件
// Mount Monitor: Editor Pinyin Input Event
const compositionStartDisposer =
state.model.on<ExpressionEditorEvent.CompositionStart>(
ExpressionEditorEvent.CompositionStart,
@@ -472,13 +472,13 @@ export const useListeners = (reducer: SuggestionReducer) => {
}),
);
return () => {
// 销毁时卸载监听器防止内存泄露
// Prevent memory leaks by uninstalling listeners when destroyed
compositionStartDisposer();
};
}, []);
useEffect(() => {
// 初始化前首次渲染激活DOM
// First render activation DOM before initialization
if (state.initialized) {
return;
}
@@ -489,7 +489,7 @@ export const useListeners = (reducer: SuggestionReducer) => {
}, []);
useEffect(() => {
// 初始化前监听到DOM激活后隐藏
// Listen to DOM activation before initialization and hide after activation
if (state.initialized || state.visible) {
return;
}
@@ -503,14 +503,14 @@ export const useListeners = (reducer: SuggestionReducer) => {
}, [state]);
};
/** 键盘上下回车键选中节点 */
/** Keyboard Enter up and down to select the node */
export const useKeyboardSelect = (
reducer: SuggestionReducer,
selectNode: (node: ExpressionEditorTreeNode) => void,
) => {
const [state, dispatch] = reducer;
// 键盘上下
// Keyboard up and down
useEffect(() => {
const keyboardArrowHandler = event => {
if (
@@ -526,34 +526,34 @@ export const useKeyboardSelect = (
}
const { optionList, selectedIndex } = uiOptions;
if (optionList.length === 1) {
// 仅有一项可选项的时候不做处理
// Do not deal with when there is only one option
return;
}
event.preventDefault();
let newIndex = selectedIndex;
if (event.key === 'ArrowDown') {
// 如果当前没有高亮的选项或者是最后一个选项,则高亮第一个选项
// If there is currently no highlighted option or the last option, highlight the first option
newIndex =
selectedIndex === -1 || selectedIndex === optionList.length - 1
? 0
: selectedIndex + 1;
} else if (event.key === 'ArrowUp') {
// 如果当前没有高亮的选项或者是第一个选项,则高亮最后一个选项
// If there is currently no highlighted option or the first option, highlight the last option
newIndex =
selectedIndex <= 0 ? optionList.length - 1 : selectedIndex - 1;
}
const selectedOption = optionList[newIndex];
// 更新高亮选项
// Update highlighting options
if (selectedIndex !== -1) {
optionList[selectedIndex].classList.remove(
SuggestionViewUtils.keyboardSelectedClassName(),
);
}
SuggestionViewUtils.setUIOptionSelected(selectedOption);
// 将新选中的选项滚动到视图中
// Scroll the newly selected option into view
selectedOption.scrollIntoView({
behavior: 'smooth', // 平滑滚动
block: 'nearest', // 最接近的视图边界,可能是顶部或底部
behavior: 'smooth', // Smooth scrolling
block: 'nearest', // The closest view boundary, possibly the top or bottom
});
};
document.addEventListener('keydown', keyboardArrowHandler);
@@ -562,7 +562,7 @@ export const useKeyboardSelect = (
};
}, [state]);
// 键盘回车
// Keyboard Enter
useEffect(() => {
const keyboardEnterHandler = event => {
if (
@@ -596,13 +596,13 @@ export const useKeyboardSelect = (
!variableTreeNode.variable?.children ||
variableTreeNode.variable?.children.length === 0
) {
// 叶子节点
// leaf node
return;
}
// 非叶子节点,光标向前移动两格
// Non-leaf node, move the cursor forward two spaces
const { selection } = state.model.editor;
if (selection && Range.isCollapsed(selection)) {
// 向前移动两个字符的光标
// Move the cursor two characters forward
Transforms.move(state.model.editor, { distance: 2, reverse: true });
}
SuggestionViewUtils.preventVisibleJitter(reducer);
@@ -613,7 +613,7 @@ export const useKeyboardSelect = (
};
}, [state]);
// 键盘 ESC 取消弹窗
// Keyboard ESC cancel pop-up window
useEffect(() => {
const keyboardESCHandler = event => {
if (
@@ -635,17 +635,17 @@ export const useKeyboardSelect = (
};
}, [state]);
// 默认选中首项
// First item selected by default
useEffect(() => {
SuggestionViewUtils.selectFirstUIOption(state);
}, [state]);
};
/** 等待semi组件数据更新后的副作用 */
/** Side effects of waiting for semi component data to be updated */
export const useRenderEffect = (reducer: SuggestionReducer) => {
const [state, dispatch] = reducer;
// 组件树状数据更新后设置搜索值
// Set the search value after the component tree data is updated
useEffect(() => {
if (!state.renderEffect.search || !state.parseData) {
return;
@@ -667,7 +667,7 @@ export const useRenderEffect = (reducer: SuggestionReducer) => {
});
}, [state]);
// 搜索过滤后是否为空
// Is it empty after searching for filters?
useEffect(() => {
if (!state.renderEffect.filtered) {
return;

View File

@@ -45,7 +45,7 @@ interface ExpressionEditorSuggestionProps {
}
/**
* 自动提示
* autoprompt
*/
export const ExpressionEditorSuggestion: FC<
ExpressionEditorSuggestionProps

View File

@@ -85,7 +85,7 @@ export const suggestionReducer = (
action.payload as SuggestionActionPayload<SuggestionActionType.SetVisible>;
if (state.entities.selectorBoxConfig) {
if (visible) {
state.entities.selectorBoxConfig.disabled = true; // 防止鼠标拖选不触发点击
state.entities.selectorBoxConfig.disabled = true; // Prevent mouse dragging from triggering clicks
}
if (!visible) {
state.entities.selectorBoxConfig.disabled = false;
@@ -166,7 +166,7 @@ export const suggestionReducer = (
return state;
};
/** 获取状态 */
/** Get status */
export const useSuggestionReducer = (
initialState: Omit<
SuggestionState,
@@ -182,15 +182,15 @@ export const useSuggestionReducer = (
): SuggestionReducer => {
const [state, dispatch]: SuggestionReducer = useReducer(suggestionReducer, {
...initialState,
initialized: false, // 初始化
version: 0, // 更新状态计数
key: 0, // 用于触发 react 重新渲染组件
variableTree: [], // 用于展示的组件树
visible: true, // 默认显示让ref能访问到DOM
hiddenDOM: true, // 默认隐藏,让用户看不到UI
allowVisibleChange: true, // 允许visible变更
initialized: false, // initialization
version: 0, // update status count
key: 0, // Used to trigger react to re-render components
variableTree: [], // Component tree for presentation
visible: true, // Default display, allowing ref to access the DOM
hiddenDOM: true, // Hidden by default, so that users cannot see the UI.
allowVisibleChange: true, // Allow visible changes
renderEffect: {
// 渲染副作用
// rendering side effects
search: false,
filtered: false,
},

View File

@@ -60,27 +60,27 @@ export class ExpressionEditorModel {
this.innerLines = ExpressionEditorParser.deserialize(initialValue);
}
/** 设置变量树 */
/** Set variable tree */
public setVariableTree(variableTree: ExpressionEditorTreeNode[]): void {
this.innerVariableTree = variableTree;
}
/** 获取变量树 */
/** Get variable tree */
public get variableTree(): ExpressionEditorTreeNode[] {
return this.innerVariableTree;
}
/** 获取行数据 */
/** Get row data */
public get lines(): ExpressionEditorLine[] {
return this.innerLines;
}
/** 获取序列化值 */
/** Get Serialized Value */
public get value(): string {
return this.innerValue;
}
/** 外部设置模型值 */
/** External setting model values */
public setValue(value: string): void {
if (value === this.innerValue) {
return;
@@ -90,22 +90,22 @@ export class ExpressionEditorModel {
this.syncEditorValue();
}
/** 同步选中状态 */
/** Synchronize selected state */
public setFocus(focus: boolean): void {
if (this.innerFocus === focus) {
return;
}
this.innerFocus = focus;
if (focus) {
// 首次选中时主动触发选区事件,主动触发变量推荐
// Active trigger selection event when first selected, active trigger variable recommendation
this.select(this.lines);
} else if (this.innerValue !== '' && this.editor.children.length !== 0) {
// 触发失焦且编辑器内容不为空,则重置选区
// Trigger out of focus and editor content is not empty, reset the selection
Transforms.select(this.editor, Editor.start(this.editor, []));
}
}
/** 注册事件 */
/** Register an event */
public on<T extends ExpressionEditorEvent>(
event: T,
callback: (params: ExpressionEditorEventParams<T>) => void,
@@ -116,7 +116,7 @@ export class ExpressionEditorModel {
};
}
/** 数据变更事件 */
/** data change event */
public change(lines: ExpressionEditorLine[]): void {
const isAstChange = this.editor.operations.some(
op => 'set_selection' !== op.type,
@@ -132,7 +132,7 @@ export class ExpressionEditorModel {
});
}
/** 选中事件 */
/** selected event */
public select(lines: ExpressionEditorLine[]): void {
const { selection } = this.editor;
if (!selection || !Range.isCollapsed(selection)) {
@@ -143,7 +143,7 @@ export class ExpressionEditorModel {
selection.anchor.path[0] !== selection.focus.path[0] ||
selection.anchor.path[1] !== selection.focus.path[1]
) {
// 框选
// box selection
this.emitter.emit(ExpressionEditorEvent.Select, {
content: '',
offset: -1,
@@ -169,7 +169,7 @@ export class ExpressionEditorModel {
});
}
/** 键盘事件 */
/** keyboard event */
public keydown(
event: Parameters<KeyboardEventHandler<HTMLDivElement>>[0],
): void {
@@ -184,7 +184,7 @@ export class ExpressionEditorModel {
reverse: true,
});
setTimeout(() => {
// slate UI 渲染滞后
// Slate UI Rendering
this.select(this.innerLines);
}, 0);
}
@@ -203,7 +203,7 @@ export class ExpressionEditorModel {
}
}
/** 开始输入拼音 */
/** Start typing pinyin */
public compositionStart(
event: CompositionEventHandler<HTMLDivElement>,
): void {
@@ -212,7 +212,7 @@ export class ExpressionEditorModel {
});
}
/** 装饰叶子节点 */
/** Decorative leaf node */
public get decorate(): ([node, path]: NodeEntry) => ExpressionEditorRange[] {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
@@ -221,7 +221,7 @@ export class ExpressionEditorModel {
if (!Text.isText(node)) {
return ranges;
}
// 计算表达式合法/非法
// Evaluation expressions are legal/illegal
const validateList = ExpressionEditorValidator.lineTextValidate({
lineText: node.text,
tree: self.innerVariableTree,
@@ -247,7 +247,7 @@ export class ExpressionEditorModel {
if (!this.innerFocus) {
return ranges;
}
// 以下是计算当前选中表达式逻辑
// The following is the logic for evaluating the currently selected expression
const selectedItem = self.isValidateSelectPath([node, path]);
const selectedValidItem = validateList.find(
validateData =>
@@ -274,17 +274,17 @@ export class ExpressionEditorModel {
}
/**
* 同步编辑器实例内容
* > **NOTICE:** *为确保不影响性能,应仅在外部值变更导致编辑器值与模型值不一致时调用*
* Synchronize editor instance content
* > ** NOTICE: ** * To ensure that performance is not affected, it should only be called when an external value change causes the editor value to be inconsistent with the model value.
*/
private syncEditorValue(): void {
// 删除编辑器内所有行
// Delete all lines in the editor
this.editor.children.forEach((line, index) => {
Transforms.removeNodes(this.editor, {
at: [index],
});
});
// 重新在编辑器插入当前行内容
// Reinsert the current line content in the editor
this.lines.forEach((line, index) => {
Transforms.insertNodes(this.editor, line, {
at: [this.editor.children.length],

View File

@@ -29,7 +29,7 @@ import {
} from '../constant';
export namespace ExpressionEditorParserBuiltin {
/** 计算开始和结束标识的序号 */
/** Calculate the serial number of the start and end tags */
export const tokenOffset = (line: {
lineContent: string;
lineOffset: number;
@@ -52,7 +52,7 @@ export namespace ExpressionEditorParserBuiltin {
firstEndTokenOffset + 2,
);
if (endChars !== ExpressionEditorToken.FullEnd) {
// 结束符号 "}}" 不完整
// End symbol "}}" is incomplete
return;
}
const lastStartTokenOffset = content.lastIndexOf(
@@ -64,7 +64,7 @@ export namespace ExpressionEditorParserBuiltin {
lastStartTokenOffset + 1,
);
if (startChars !== ExpressionEditorToken.FullStart) {
// 开始符号 "{{" 不完整
// The opening symbol "{{" is incomplete
return;
}
return {
@@ -73,7 +73,7 @@ export namespace ExpressionEditorParserBuiltin {
};
};
/** 从行内容提取内容 */
/** Extract content from line content */
export const extractContent = (params: {
lineContent: string;
lineOffset: number;
@@ -102,7 +102,7 @@ export namespace ExpressionEditorParserBuiltin {
};
};
/** 根据 offset 将文本内容切分为可用与不可用 */
/** Split text content into available and unavailable by offset */
export const sliceReachable = (params: {
content: string;
offset: number;
@@ -119,29 +119,29 @@ export namespace ExpressionEditorParserBuiltin {
};
};
/** 切分文本 */
/** Split text */
export const splitText = (pathString: string): string[] => {
// 得到的分割数组,初始为原字符串以"."分割的结果
// The obtained split array, initially the result of splitting the original string with "."
const segments = pathString.split(ExpressionEditorToken.Separator);
// 定义结果数组,并处理连续的"."导致的空字符串
// Define the result array and handle empty strings resulting from consecutive "."
const result: string[] = [];
segments.forEach(segment => {
if (!segment.match(/\[\d+\]/)) {
// 如果不是数组索引,直接加入结果数组,即使是空字符串也加入以保持正确的分割
// If it is not an array index, add the result array directly, even if it is an empty string, to maintain the correct segmentation
result.push(segment);
return;
}
// 如果当前段是数组索引,将前面的字符串和当前数组索引分别加入结果数组
// If the current segment is an array index, add the previous string and the current array index to the result array, respectively
const lastSegmentIndex = segment.lastIndexOf(
ExpressionEditorToken.ArrayStart,
);
const key = segment.substring(0, lastSegmentIndex);
const index = segment.substring(lastSegmentIndex);
// {{array[0]}} 中的 array
// Array in {{array [0]}}
result.push(key);
// {{array[0]}} 中的 [0]
// [0] in {{array [0]}}
result.push(index);
return;
});
@@ -149,14 +149,14 @@ export namespace ExpressionEditorParserBuiltin {
return result;
};
/** 字符串解析为路径 */
/** String parsed as path */
export const toSegments = (
text: string,
): ExpressionEditorSegment[] | undefined => {
const textSegments = ExpressionEditorParserBuiltin.splitText(text);
const segments: ExpressionEditorSegment[] = [];
const validate = textSegments.every((textSegment, index) => {
// 数组下标
// array subscript
if (
textSegment.startsWith(ExpressionEditorToken.ArrayStart) &&
textSegment.endsWith(ExpressionEditorToken.ArrayEnd)
@@ -164,7 +164,7 @@ export namespace ExpressionEditorParserBuiltin {
const arrayIndexString = textSegment.slice(1, -1);
const arrayIndex = Number(arrayIndexString);
if (arrayIndexString === '' || Number.isNaN(arrayIndex)) {
// index 必须是数字
// Index must be a number
return false;
}
const lastSegment = segments[segments.length - 1];
@@ -172,7 +172,7 @@ export namespace ExpressionEditorParserBuiltin {
!lastSegment ||
lastSegment.type !== ExpressionEditorSegmentType.ObjectKey
) {
// 数组索引必须在 key 之后
// The array index must be after the key
return false;
}
segments.push({
@@ -181,7 +181,7 @@ export namespace ExpressionEditorParserBuiltin {
arrayIndex,
});
}
// 最后一行空文本
// The last empty line of text
else if (index === textSegments.length - 1 && textSegment === '') {
segments.push({
type: ExpressionEditorSegmentType.EndEmpty,
@@ -207,11 +207,11 @@ export namespace ExpressionEditorParserBuiltin {
}
export namespace ExpressionEditorParser {
/** 序列化 */
/** Serialization */
export const serialize = (value: ExpressionEditorLine[]) =>
value.map(n => Node.string(n)).join('\n');
/** 反序列化 */
/** deserialization */
export const deserialize = (text: string): ExpressionEditorLine[] => {
const lines = text.split('\n');
return lines.map(line => ({

View File

@@ -165,7 +165,7 @@ export namespace ExpressionEditorTreeHelper {
const lastSegment = segments[segments.length - 1];
const segmentsRemovedLast =
lastSegment.type === ExpressionEditorSegmentType.ArrayIndex
? segments.slice(0, segments.length - 2) // 数组索引属于上一层级,需要去除两层
? segments.slice(0, segments.length - 2) // The array index belongs to the previous level, and two layers need to be removed.
: segments.slice(0, segments.length - 1);
let treeLayer = tree;
segmentsRemovedLast.forEach(segment => {
@@ -193,7 +193,7 @@ export namespace ExpressionEditorTreeHelper {
const pathList: { objectKey: string; arrayIndex?: number }[] = [];
while (current) {
if (current.variable?.type === ViewVariableType.ArrayObject) {
// 默认第0个
// Default 0th
pathList.unshift({
objectKey: current.label,
arrayIndex: 0,
@@ -213,7 +213,7 @@ export namespace ExpressionEditorTreeHelper {
const pathItem = pathList[pathIndex];
pathIndex++;
if (pathItem.objectKey !== segment.objectKey) {
// 退出循环
// exit the loop
return true;
}
const nextSegment = segments[index + 1];
@@ -253,7 +253,7 @@ export namespace ExpressionEditorTreeHelper {
return false;
};
const beforeTreeNode = treeBranch[treeBranch.length - 1];
// 确认非法情况:是否对非数组类型使用数组索引
// Verify Illegal Case: Whether to Use Array Indexing for Non-Array Types
if (
segment.type === ExpressionEditorSegmentType.ArrayIndex &&
beforeTreeNode &&
@@ -262,7 +262,7 @@ export namespace ExpressionEditorTreeHelper {
) {
return itemInvalid();
}
// 确认非法情况:数组只能跟随数组下标
// Confirm illegal condition: Array can only follow array subscript
if (
beforeTreeNode?.variable?.type &&
ViewVariableType.isArrayType(beforeTreeNode.variable.type) &&
@@ -270,12 +270,12 @@ export namespace ExpressionEditorTreeHelper {
) {
return itemInvalid();
}
// 忽略
// ignore
if (segment.type !== ExpressionEditorSegmentType.ObjectKey) {
return itemValid();
}
const treeNode = treeLayer.find(node => node.label === segment.objectKey);
// 确认非法情况:每一个 object key 必须对应一个 variable node
// Verify illegal condition: each object key must correspond to a variable node
if (!treeNode) {
return itemInvalid();
}