- rendererLogs: inline IPC channel constants to fix boundary violation - EditorFileWatcher/TaskBoundaryParser: rename UPPER_CASE class props to camelCase - TeamConfigReader: remove unused readFileHead/extractQuotedString functions - TeamFsWorkerClient: use crypto.randomUUID(), remove duplicated branches - team-fs-worker: full type safety rewrite — 10 interfaces replacing ~150 any casts, extract readTasksDirForTeam diagnostics to avoid param reassign - useDiffNavigation/editorSlice/buildSelectionAction: add missing return types - useFileSuggestions: suppress intentional setState-in-effect - store/index: suppress intentional deprecated navigator.platform fallback - platformPath: replace vulnerable regexes with manual loops
116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
/**
|
|
* Builds an EditorSelectionAction from a selection info + action type.
|
|
*
|
|
* Extracted as a utility so it can be imported in tests
|
|
* without pulling in CodeMirror dependencies.
|
|
*/
|
|
|
|
import { getBasename, isWindowsishPath, splitPath } from '@shared/utils/platformPath';
|
|
|
|
import type { EditorSelectionAction, EditorSelectionInfo } from '@shared/types/editor';
|
|
|
|
// =============================================================================
|
|
// Code fence language map (lowercase identifiers for markdown)
|
|
// =============================================================================
|
|
|
|
const CODE_FENCE_LANG: Record<string, string> = {
|
|
ts: 'typescript',
|
|
tsx: 'tsx',
|
|
js: 'javascript',
|
|
jsx: 'jsx',
|
|
mjs: 'javascript',
|
|
cjs: 'javascript',
|
|
py: 'python',
|
|
json: 'json',
|
|
jsonl: 'json',
|
|
css: 'css',
|
|
scss: 'scss',
|
|
sass: 'sass',
|
|
less: 'less',
|
|
html: 'html',
|
|
htm: 'html',
|
|
xml: 'xml',
|
|
svg: 'xml',
|
|
md: 'markdown',
|
|
mdx: 'markdown',
|
|
yaml: 'yaml',
|
|
yml: 'yaml',
|
|
rs: 'rust',
|
|
go: 'go',
|
|
java: 'java',
|
|
c: 'c',
|
|
h: 'c',
|
|
cpp: 'cpp',
|
|
cxx: 'cpp',
|
|
cc: 'cpp',
|
|
hpp: 'cpp',
|
|
php: 'php',
|
|
sql: 'sql',
|
|
sh: 'bash',
|
|
bash: 'bash',
|
|
zsh: 'bash',
|
|
toml: 'toml',
|
|
ini: 'ini',
|
|
};
|
|
|
|
/** Maps file extension to a code fence language identifier (lowercase). */
|
|
export function getCodeFenceLanguage(fileName: string): string {
|
|
const ext = fileName.split('.').pop()?.toLowerCase() ?? '';
|
|
return CODE_FENCE_LANG[ext] ?? '';
|
|
}
|
|
|
|
/**
|
|
* Builds a file-mention action (no code selection, just the file reference).
|
|
* Used when triggering "Create Task" / "Write Teammate" from the file tree context menu.
|
|
*/
|
|
export function buildFileAction(
|
|
type: EditorSelectionAction['type'],
|
|
filePath: string,
|
|
projectPath?: string | null
|
|
): EditorSelectionAction {
|
|
const fileName = getBasename(filePath) || 'file';
|
|
let displayPath = filePath;
|
|
if (projectPath) {
|
|
const fullParts = splitPath(filePath);
|
|
const rootParts = splitPath(projectPath);
|
|
const win = isWindowsishPath(projectPath);
|
|
const eq = (a: string, b: string): boolean =>
|
|
win ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
const hasPrefix =
|
|
fullParts.length >= rootParts.length && rootParts.every((seg, i) => eq(seg, fullParts[i]));
|
|
if (hasPrefix) {
|
|
displayPath = fullParts.slice(rootParts.length).join('/');
|
|
}
|
|
}
|
|
return {
|
|
type,
|
|
filePath,
|
|
fromLine: null,
|
|
toLine: null,
|
|
selectedText: '',
|
|
formattedContext: `**${fileName}** (\`${displayPath}\`)`,
|
|
displayPath,
|
|
};
|
|
}
|
|
|
|
/** Builds a selection action with a formatted markdown code fence context. */
|
|
export function buildSelectionAction(
|
|
type: EditorSelectionAction['type'],
|
|
info: EditorSelectionInfo
|
|
): EditorSelectionAction {
|
|
const fileName = getBasename(info.filePath) || 'file';
|
|
const lang = getCodeFenceLanguage(fileName);
|
|
const lineRef =
|
|
info.fromLine === info.toLine
|
|
? `line ${info.fromLine}`
|
|
: `lines ${info.fromLine}-${info.toLine}`;
|
|
const formattedContext = `**${fileName}** (${lineRef}):\n\`\`\`${lang}\n${info.text}\n\`\`\``;
|
|
return {
|
|
type,
|
|
filePath: info.filePath,
|
|
fromLine: info.fromLine,
|
|
toLine: info.toLine,
|
|
selectedText: info.text,
|
|
formattedContext,
|
|
};
|
|
}
|