🎨 Add variable support for http client

This commit is contained in:
2025-11-02 17:20:22 +08:00
parent 4380ad010c
commit 5688304817
12 changed files with 1704 additions and 391 deletions

View File

@@ -1,6 +1,7 @@
import { EditorState } from '@codemirror/state';
import { syntaxTree } from '@codemirror/language';
import type { SyntaxNode } from '@lezer/common';
import { VariableResolver } from './variable-resolver';
/**
* HTTP 请求模型
@@ -53,13 +54,36 @@ const NODE_TYPES = {
TEXT_KEYWORD: 'TextKeyword',
JSON_BLOCK: 'JsonBlock',
JSON_PROPERTY: 'JsonProperty',
VARIABLE_REF: 'VariableRef',
} as const;
/**
* HTTP 请求解析器
*/
export class HttpRequestParser {
constructor(private state: EditorState) {}
private variableResolver: VariableResolver | null = null;
/**
* 构造函数
* @param state EditorState
* @param blockRange 块的范围(可选),如果提供则只解析该块内的变量
*/
constructor(
private state: EditorState,
private blockRange?: { from: number; to: number }
) {
}
/**
* 获取或创建变量解析器(懒加载)
*/
private getVariableResolver(): VariableResolver {
if (!this.variableResolver) {
this.variableResolver = new VariableResolver(this.state, this.blockRange);
}
return this.variableResolver;
}
/**
* 解析指定位置的 HTTP 请求
@@ -152,7 +176,9 @@ export class HttpRequestParser {
private parseUrl(node: SyntaxNode): string {
const urlText = this.getNodeText(node);
// 移除引号
return urlText.replace(/^["']|["']$/g, '');
const url = urlText.replace(/^["']|["']$/g, '');
// 替换变量
return this.getVariableResolver().replaceVariables(url);
}
/**
@@ -236,12 +262,13 @@ export class HttpRequestParser {
const name = this.getNodeText(nameNode);
// 尝试获取值节点String, Number, JsonBlock
// 尝试获取值节点String, Number, JsonBlock, VariableRef
let value: any = null;
for (let child = node.firstChild; child; child = child.nextSibling) {
if (child.name === NODE_TYPES.STRING_LITERAL ||
child.name === NODE_TYPES.NUMBER_LITERAL ||
child.name === NODE_TYPES.JSON_BLOCK ||
child.name === NODE_TYPES.VARIABLE_REF ||
child.name === NODE_TYPES.IDENTIFIER) {
value = this.parseValue(child);
return { name, value };
@@ -305,20 +332,36 @@ export class HttpRequestParser {
}
}
// HTTP Header 的值必须转换为字符串
if (value !== null && value !== undefined) {
value = String(value);
}
return { name, value };
}
/**
* 解析值节点(字符串、数字、标识符、嵌套块)
* 解析值节点(字符串、数字、标识符、嵌套块、变量引用
*/
private parseValue(node: SyntaxNode): any {
if (node.name === NODE_TYPES.STRING_LITERAL) {
const text = this.getNodeText(node);
// 移除引号
return text.replace(/^["']|["']$/g, '');
const value = text.replace(/^["']|["']$/g, '');
// 替换字符串中的变量
return this.getVariableResolver().replaceVariables(value);
} else if (node.name === NODE_TYPES.NUMBER_LITERAL) {
const text = this.getNodeText(node);
return parseFloat(text);
} else if (node.name === NODE_TYPES.VARIABLE_REF) {
// 处理变量引用节点
const text = this.getNodeText(node);
const resolver = this.getVariableResolver();
const ref = resolver.parseVariableRef(text);
if (ref) {
return resolver.resolveVariable(ref.name, ref.defaultValue);
}
return text;
} else if (node.name === NODE_TYPES.IDENTIFIER) {
const text = this.getNodeText(node);
// 处理布尔值
@@ -347,9 +390,16 @@ export class HttpRequestParser {
/**
* 便捷函数:解析指定位置的 HTTP 请求
* @param state EditorState
* @param pos 光标位置
* @param blockRange 块的范围(可选),如果提供则只解析该块内的变量
*/
export function parseHttpRequest(state: EditorState, pos: number): HttpRequest | null {
const parser = new HttpRequestParser(state);
export function parseHttpRequest(
state: EditorState,
pos: number,
blockRange?: { from: number; to: number }
): HttpRequest | null {
const parser = new HttpRequestParser(state, blockRange);
return parser.parseRequestAt(pos);
}