feat(editor): 新增 buildRunnableInfo 构造 runnable fence info string

纯函数,把语言+overrides 配置转成 'python runnable {...}' 形态。
dirty=false 省略 JSON,dirty=true 写 timeout/memory/network 三项,
字段顺序固定。
This commit is contained in:
xfy 2026-07-06 13:39:46 +08:00
parent 89bab26b90
commit 84b3da9db6
2 changed files with 79 additions and 0 deletions

View File

@ -0,0 +1,48 @@
import { describe, expect, it } from 'vitest';
import { buildRunnableInfo } from '../slash-command';
/**
* buildRunnableInfo 测试:把弹框收集的配置转成 fence info string
*
* dirty=false() 'python runnable'( JSON)
* dirty=true 'python runnable {"timeout_secs":N,"memory_mb":M,"allow_network":B}'
* JSON 字段顺序固定:timeout memory network
*/
describe('buildRunnableInfo', () => {
const base = {
lang: 'python',
timeoutSecs: 5,
memoryMb: 256,
allowNetwork: false,
} as const;
describe('dirty=false(全默认,省略 JSON)', () => {
it('python → "python runnable"', () => {
expect(buildRunnableInfo({ ...base, dirty: false })).toBe('python runnable');
});
it('node → "node runnable"', () => {
expect(buildRunnableInfo({ ...base, lang: 'node', dirty: false })).toBe('node runnable');
});
});
describe('dirty=true(写 JSON)', () => {
it('改了 timeout,JSON 含全部 3 项', () => {
expect(buildRunnableInfo({ ...base, timeoutSecs: 10, dirty: true })).toBe(
'python runnable {"timeout_secs":10,"memory_mb":256,"allow_network":false}',
);
});
it('node + 改了 allow_network', () => {
expect(buildRunnableInfo({ ...base, lang: 'node', allowNetwork: true, dirty: true })).toBe(
'node runnable {"timeout_secs":5,"memory_mb":256,"allow_network":true}',
);
});
it('JSON 字段顺序固定(timeout→memory→network)', () => {
const out = buildRunnableInfo({ ...base, dirty: true });
const jsonStart = out.indexOf('{');
const jsonEnd = out.lastIndexOf('}') + 1;
const keys = Object.keys(JSON.parse(out.slice(jsonStart, jsonEnd)));
expect(keys).toEqual(['timeout_secs', 'memory_mb', 'allow_network']);
});
});
});

View File

@ -363,3 +363,34 @@ function createPopup(props: SuggestionProps<CommandItem>): SlashPopup {
}, },
}; };
} }
/** buildRunnableInfo 的输入配置。 */
export interface RunnableInfoOpts {
/** 语言名python / node。 */
lang: string;
/** 超时秒数。 */
timeoutSecs: number;
/** 内存上限MB。 */
memoryMb: number;
/** 是否允许网络。 */
allowNetwork: boolean;
/** 作者是否改动过任一 overrides 字段false 则省略 JSON。 */
dirty: boolean;
}
/**
* markdown fence info string
*
* - dirty=false `${lang} runnable` JSON
* - dirty=true `${lang} runnable {"timeout_secs":N,"memory_mb":M,"allow_network":B}`
*
* JSON timeout memory network
* disabled
*/
export function buildRunnableInfo(opts: RunnableInfoOpts): string {
const prefix = `${opts.lang} runnable`;
if (!opts.dirty) return prefix;
// 显式拼字符串保证字段顺序固定timeout → memory → network不依赖对象键序。
const json = `{"timeout_secs":${opts.timeoutSecs},"memory_mb":${opts.memoryMb},"allow_network":${opts.allowNetwork}}`;
return `${prefix} ${json}`;
}