fix: 修复管理端前端 lint 与构建问题
- 收敛 easyflow-ui-admin 的 lint、格式和类型问题 - 修正 demo 页面与管理端前端构建失败点 - 验证 pnpm lint 与 pnpm build 均已通过
This commit is contained in:
@@ -1,272 +1,292 @@
|
||||
export interface ParameterLike {
|
||||
name?: string;
|
||||
ref?: string;
|
||||
refType?: string;
|
||||
children?: ParameterLike[];
|
||||
name?: string;
|
||||
ref?: string;
|
||||
refType?: string;
|
||||
children?: ParameterLike[];
|
||||
}
|
||||
|
||||
export interface TokenRange {
|
||||
start: number;
|
||||
end: number;
|
||||
text: string;
|
||||
key: string;
|
||||
start: number;
|
||||
end: number;
|
||||
text: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export type TokenPart =
|
||||
| {
|
||||
type: 'text';
|
||||
text: string;
|
||||
}
|
||||
| {
|
||||
type: 'token';
|
||||
text: string;
|
||||
key: string;
|
||||
valid: boolean;
|
||||
};
|
||||
| {
|
||||
type: 'text';
|
||||
text: string;
|
||||
}
|
||||
| {
|
||||
type: 'token';
|
||||
text: string;
|
||||
key: string;
|
||||
valid: boolean;
|
||||
};
|
||||
|
||||
export interface ParameterCandidate {
|
||||
name: string;
|
||||
resolved: boolean;
|
||||
name: string;
|
||||
resolved: boolean;
|
||||
}
|
||||
|
||||
const TOKEN_PATTERN = /\{\{\s*([^{}]+?)\s*}}/g;
|
||||
|
||||
export function normalizeTokenKey(tokenKey: string): string {
|
||||
return tokenKey.trim();
|
||||
return tokenKey.trim();
|
||||
}
|
||||
|
||||
export function flattenParameterNames(parameters?: ParameterLike[] | null): string[] {
|
||||
return flattenParameterCandidates(parameters).map((item) => item.name);
|
||||
export function flattenParameterNames(
|
||||
parameters?: ParameterLike[] | null,
|
||||
): string[] {
|
||||
return flattenParameterCandidates(parameters).map((item) => item.name);
|
||||
}
|
||||
|
||||
function isParameterResolved(parameter?: ParameterLike): boolean {
|
||||
if (!parameter) {
|
||||
return false;
|
||||
}
|
||||
if (!parameter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const refType = (parameter.refType || '').trim();
|
||||
if (refType === 'fixed' || refType === 'input') {
|
||||
return true;
|
||||
}
|
||||
const refType = (parameter.refType || '').trim();
|
||||
if (refType === 'fixed' || refType === 'input') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ref = (parameter.ref || '').trim();
|
||||
return !!ref;
|
||||
const ref = (parameter.ref || '').trim();
|
||||
return !!ref;
|
||||
}
|
||||
|
||||
export function flattenParameterCandidates(parameters?: ParameterLike[] | null): ParameterCandidate[] {
|
||||
if (!parameters || parameters.length === 0) {
|
||||
return [];
|
||||
export function flattenParameterCandidates(
|
||||
parameters?: ParameterLike[] | null,
|
||||
): ParameterCandidate[] {
|
||||
if (!parameters || parameters.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const candidates: ParameterCandidate[] = [];
|
||||
const indexMap = new Map<string, number>();
|
||||
|
||||
const addCandidate = (name: string, resolved: boolean) => {
|
||||
const normalized = name.trim();
|
||||
if (!normalized) {
|
||||
return;
|
||||
}
|
||||
const exists = indexMap.get(normalized);
|
||||
if (exists === undefined) {
|
||||
indexMap.set(normalized, candidates.length);
|
||||
candidates.push({
|
||||
name: normalized,
|
||||
resolved,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const candidates: ParameterCandidate[] = [];
|
||||
const indexMap = new Map<string, number>();
|
||||
// 同名参数只要有一个可解析,就视为可解析
|
||||
if (resolved) {
|
||||
candidates[exists].resolved = true;
|
||||
}
|
||||
};
|
||||
|
||||
const addCandidate = (name: string, resolved: boolean) => {
|
||||
const normalized = name.trim();
|
||||
if (!normalized) {
|
||||
return;
|
||||
}
|
||||
const exists = indexMap.get(normalized);
|
||||
if (exists === undefined) {
|
||||
indexMap.set(normalized, candidates.length);
|
||||
candidates.push({
|
||||
name: normalized,
|
||||
resolved
|
||||
});
|
||||
return;
|
||||
}
|
||||
const walk = (
|
||||
items: ParameterLike[],
|
||||
parentPath = '',
|
||||
inheritedResolved = true,
|
||||
) => {
|
||||
for (const item of items) {
|
||||
const rawName = item?.name?.trim();
|
||||
if (!rawName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 同名参数只要有一个可解析,就视为可解析
|
||||
if (resolved) {
|
||||
candidates[exists].resolved = true;
|
||||
}
|
||||
};
|
||||
const currentPath = parentPath ? `${parentPath}.${rawName}` : rawName;
|
||||
const currentResolved = inheritedResolved && isParameterResolved(item);
|
||||
addCandidate(currentPath, currentResolved);
|
||||
|
||||
const walk = (items: ParameterLike[], parentPath = '', inheritedResolved = true) => {
|
||||
for (const item of items) {
|
||||
const rawName = item?.name?.trim();
|
||||
if (!rawName) {
|
||||
continue;
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
walk(item.children, currentPath, currentResolved);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const currentPath = parentPath ? `${parentPath}.${rawName}` : rawName;
|
||||
const currentResolved = inheritedResolved && isParameterResolved(item);
|
||||
addCandidate(currentPath, currentResolved);
|
||||
|
||||
if (item.children && item.children.length > 0) {
|
||||
walk(item.children, currentPath, currentResolved);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walk(parameters);
|
||||
return candidates;
|
||||
walk(parameters);
|
||||
return candidates;
|
||||
}
|
||||
|
||||
export function parseTokenParts(content: string, validParams: string[] = []): TokenPart[] {
|
||||
const source = content ?? '';
|
||||
const validSet = new Set(validParams.map(normalizeTokenKey));
|
||||
const parts: TokenPart[] = [];
|
||||
export function parseTokenParts(
|
||||
content: string,
|
||||
validParams: string[] = [],
|
||||
): TokenPart[] {
|
||||
const source = content ?? '';
|
||||
const validSet = new Set(validParams.map(normalizeTokenKey));
|
||||
const parts: TokenPart[] = [];
|
||||
|
||||
let lastIndex = 0;
|
||||
TOKEN_PATTERN.lastIndex = 0;
|
||||
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
|
||||
let lastIndex = 0;
|
||||
TOKEN_PATTERN.lastIndex = 0;
|
||||
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
|
||||
|
||||
while (match) {
|
||||
if (match.index > lastIndex) {
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: source.slice(lastIndex, match.index)
|
||||
});
|
||||
}
|
||||
|
||||
const rawToken = match[0];
|
||||
const tokenKey = normalizeTokenKey(match[1] || '');
|
||||
parts.push({
|
||||
type: 'token',
|
||||
text: rawToken,
|
||||
key: tokenKey,
|
||||
valid: validSet.has(tokenKey)
|
||||
});
|
||||
|
||||
lastIndex = match.index + rawToken.length;
|
||||
match = TOKEN_PATTERN.exec(source);
|
||||
while (match) {
|
||||
if (match.index > lastIndex) {
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: source.slice(lastIndex, match.index),
|
||||
});
|
||||
}
|
||||
|
||||
if (lastIndex < source.length) {
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: source.slice(lastIndex)
|
||||
});
|
||||
}
|
||||
const rawToken = match[0];
|
||||
const tokenKey = normalizeTokenKey(match[1] || '');
|
||||
parts.push({
|
||||
type: 'token',
|
||||
text: rawToken,
|
||||
key: tokenKey,
|
||||
valid: validSet.has(tokenKey),
|
||||
});
|
||||
|
||||
if (parts.length === 0) {
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: source
|
||||
});
|
||||
}
|
||||
lastIndex = match.index + rawToken.length;
|
||||
match = TOKEN_PATTERN.exec(source);
|
||||
}
|
||||
|
||||
return parts;
|
||||
if (lastIndex < source.length) {
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: source.slice(lastIndex),
|
||||
});
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: source,
|
||||
});
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
export function getTokenRanges(content: string): TokenRange[] {
|
||||
const source = content ?? '';
|
||||
const ranges: TokenRange[] = [];
|
||||
TOKEN_PATTERN.lastIndex = 0;
|
||||
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
|
||||
const source = content ?? '';
|
||||
const ranges: TokenRange[] = [];
|
||||
TOKEN_PATTERN.lastIndex = 0;
|
||||
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
|
||||
|
||||
while (match) {
|
||||
const rawToken = match[0];
|
||||
ranges.push({
|
||||
start: match.index,
|
||||
end: match.index + rawToken.length,
|
||||
text: rawToken,
|
||||
key: normalizeTokenKey(match[1] || '')
|
||||
});
|
||||
match = TOKEN_PATTERN.exec(source);
|
||||
}
|
||||
while (match) {
|
||||
const rawToken = match[0];
|
||||
ranges.push({
|
||||
start: match.index,
|
||||
end: match.index + rawToken.length,
|
||||
text: rawToken,
|
||||
key: normalizeTokenKey(match[1] || ''),
|
||||
});
|
||||
match = TOKEN_PATTERN.exec(source);
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return ranges;
|
||||
}
|
||||
|
||||
export function findTokenRangeAtCursor(
|
||||
content: string,
|
||||
cursor: number,
|
||||
options?: {
|
||||
includeStart?: boolean;
|
||||
includeEnd?: boolean;
|
||||
}
|
||||
content: string,
|
||||
cursor: number,
|
||||
options?: {
|
||||
includeStart?: boolean;
|
||||
includeEnd?: boolean;
|
||||
},
|
||||
): TokenRange | null {
|
||||
if (!Number.isInteger(cursor) || cursor < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const includeStart = options?.includeStart ?? false;
|
||||
const includeEnd = options?.includeEnd ?? false;
|
||||
const ranges = getTokenRanges(content);
|
||||
for (const range of ranges) {
|
||||
const leftValid = includeStart ? cursor >= range.start : cursor > range.start;
|
||||
const rightValid = includeEnd ? cursor <= range.end : cursor < range.end;
|
||||
if (leftValid && rightValid) {
|
||||
return range;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Number.isInteger(cursor) || cursor < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const includeStart = options?.includeStart ?? false;
|
||||
const includeEnd = options?.includeEnd ?? false;
|
||||
const ranges = getTokenRanges(content);
|
||||
for (const range of ranges) {
|
||||
const leftValid = includeStart
|
||||
? cursor >= range.start
|
||||
: cursor > range.start;
|
||||
const rightValid = includeEnd ? cursor <= range.end : cursor < range.end;
|
||||
if (leftValid && rightValid) {
|
||||
return range;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findBackspaceTokenRange(content: string, cursor: number): TokenRange | null {
|
||||
return findTokenRangeAtCursor(content, cursor, {
|
||||
includeStart: false,
|
||||
includeEnd: true
|
||||
});
|
||||
export function findBackspaceTokenRange(
|
||||
content: string,
|
||||
cursor: number,
|
||||
): TokenRange | null {
|
||||
return findTokenRangeAtCursor(content, cursor, {
|
||||
includeStart: false,
|
||||
includeEnd: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function splitTokenDisplay(rawToken: string, normalizedKey?: string): {
|
||||
hiddenPrefix: string;
|
||||
visibleText: string;
|
||||
hiddenSuffix: string;
|
||||
export function splitTokenDisplay(
|
||||
rawToken: string,
|
||||
normalizedKey?: string,
|
||||
): {
|
||||
hiddenPrefix: string;
|
||||
visibleText: string;
|
||||
hiddenSuffix: string;
|
||||
} {
|
||||
const source = rawToken ?? '';
|
||||
if (!source.startsWith('{{') || !source.endsWith('}}')) {
|
||||
return {
|
||||
hiddenPrefix: '',
|
||||
visibleText: normalizedKey || source,
|
||||
hiddenSuffix: ''
|
||||
};
|
||||
}
|
||||
|
||||
const inner = source.slice(2, -2);
|
||||
const visibleText = normalizeTokenKey(normalizedKey || inner);
|
||||
if (!visibleText) {
|
||||
return {
|
||||
hiddenPrefix: '',
|
||||
visibleText: source,
|
||||
hiddenSuffix: ''
|
||||
};
|
||||
}
|
||||
|
||||
const innerStart = inner.indexOf(visibleText);
|
||||
const leading = innerStart >= 0 ? inner.slice(0, innerStart) : '';
|
||||
const trailing = innerStart >= 0 ? inner.slice(innerStart + visibleText.length) : '';
|
||||
|
||||
const source = rawToken ?? '';
|
||||
if (!source.startsWith('{{') || !source.endsWith('}}')) {
|
||||
return {
|
||||
hiddenPrefix: `{{${leading}`,
|
||||
visibleText,
|
||||
hiddenSuffix: `${trailing}}}`
|
||||
hiddenPrefix: '',
|
||||
visibleText: normalizedKey || source,
|
||||
hiddenSuffix: '',
|
||||
};
|
||||
}
|
||||
|
||||
const inner = source.slice(2, -2);
|
||||
const visibleText = normalizeTokenKey(normalizedKey || inner);
|
||||
if (!visibleText) {
|
||||
return {
|
||||
hiddenPrefix: '',
|
||||
visibleText: source,
|
||||
hiddenSuffix: '',
|
||||
};
|
||||
}
|
||||
|
||||
const innerStart = inner.indexOf(visibleText);
|
||||
const leading = innerStart >= 0 ? inner.slice(0, innerStart) : '';
|
||||
const trailing =
|
||||
innerStart >= 0 ? inner.slice(innerStart + visibleText.length) : '';
|
||||
|
||||
return {
|
||||
hiddenPrefix: `{{${leading}`,
|
||||
visibleText,
|
||||
hiddenSuffix: `${trailing}}}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function insertTextAtCursor(
|
||||
content: string,
|
||||
insertedText: string,
|
||||
selectionStart?: number | null,
|
||||
selectionEnd?: number | null
|
||||
content: string,
|
||||
insertedText: string,
|
||||
selectionStart?: number | null,
|
||||
selectionEnd?: number | null,
|
||||
): {
|
||||
value: string;
|
||||
cursor: number;
|
||||
value: string;
|
||||
cursor: number;
|
||||
} {
|
||||
const source = content ?? '';
|
||||
const start = Number.isInteger(selectionStart)
|
||||
? Math.max(0, Math.min(selectionStart as number, source.length))
|
||||
: source.length;
|
||||
const end = Number.isInteger(selectionEnd)
|
||||
? Math.max(start, Math.min(selectionEnd as number, source.length))
|
||||
: start;
|
||||
const source = content ?? '';
|
||||
const start = Number.isInteger(selectionStart)
|
||||
? Math.max(0, Math.min(selectionStart as number, source.length))
|
||||
: source.length;
|
||||
const end = Number.isInteger(selectionEnd)
|
||||
? Math.max(start, Math.min(selectionEnd as number, source.length))
|
||||
: start;
|
||||
|
||||
const nextValue = source.slice(0, start) + insertedText + source.slice(end);
|
||||
return {
|
||||
value: nextValue,
|
||||
cursor: start + insertedText.length
|
||||
};
|
||||
const nextValue = source.slice(0, start) + insertedText + source.slice(end);
|
||||
return {
|
||||
value: nextValue,
|
||||
cursor: start + insertedText.length,
|
||||
};
|
||||
}
|
||||
|
||||
export function escapeHtml(text: string): string {
|
||||
return text
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll("'", ''');
|
||||
return text
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll("'", ''');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user