diff options
| author | David Czihak <git@dcz.at> | 2026-05-08 21:15:49 +0200 |
|---|---|---|
| committer | David Czihak <git@dcz.at> | 2026-05-08 21:15:49 +0200 |
| commit | 31ef0db515770896f5708aeeadadb211ccf3d3b3 (patch) | |
| tree | e233f78275932b81ae3c57965c53bb1b016373f5 | |
| parent | 8ddd84baba48df6c146f2d15fd017d7928473d41 (diff) | |
Docs: Add JSDoc comments to utility functions
| -rw-r--r-- | Scripts/main.js | 154 |
1 files changed, 148 insertions, 6 deletions
diff --git a/Scripts/main.js b/Scripts/main.js index 944eb62..a1c86f6 100644 --- a/Scripts/main.js +++ b/Scripts/main.js @@ -51,6 +51,11 @@ exports.deactivate = function deactivate() { commandRegistrations = []; }; +/** + * Resolve a configuration value respecting precedence + * + * @param {string} key - Configuration key + */ function getConfigValue(key) { const workspaceValue = nova.workspace.config.get(key); if ( @@ -69,6 +74,12 @@ function getConfigValue(key) { return null; } +/** + * Resolve a configuration boolean value respecting precedence + * + * @param {string} key - Configuration key + * @param {boolean} fallback - Fallback value + */ function getBooleanConfigValue(key, fallback) { const workspaceValue = nova.workspace.config.get(key); if (typeof workspaceValue === "boolean") { @@ -83,6 +94,13 @@ function getBooleanConfigValue(key, fallback) { return fallback; } +/** + * Normalize a config array value by converting to array, filtering nulls, + * trimming whitespace, and removing empty entries + * + * @param {*} value - Any value + * @returns {string[]} - Clean array of non-empty strings + */ function normalizeArray(value) { if (!Array.isArray(value)) { return []; @@ -122,6 +140,13 @@ function resolvePathAgainstBase(path, base) { return path; } +/** + * Safely retrieve a task config value + * + * @param {task configuration object} config - Task configuration + * @param {string} key - Key + * @returns {string} - Value + */ function getTaskConfigValue(config, key) { if (!config) { return null; @@ -131,10 +156,25 @@ function getTaskConfigValue(config, key) { return value === undefined || value === null || value === "" ? null : value; } +/** + * Safely retrieve a task config argument list + * + * Specialized version of {@link getTaskConfigValue} + * + * @param {task configuration object} config - Task configuration + * @param {string} key - Key + * @returns {string[]} - Argument list + */ function getTaskArgs(config, key) { return normalizeArray(getTaskConfigValue(config, key)); } +/** + * Resolves the task working directory from config, falling back to workspace root. + * + * @param {Object} config - Nova task configuration object + * @returns {string|null} - Absolute working directory path or null if no workspace is open + */ function getTaskCwd(config) { const configured = getTaskConfigValue(config, "cwd"); if (configured) { @@ -197,8 +237,14 @@ function buildZigArgv(config, options) { return argv; } -// Refuses to clean unless `cwd` is non-root, not $HOME, and inside the workspace. -// Returns the array of cache directories to remove, or null after warning the user. +/** + * Validate cwd is safe to clean (absolute, inside workspace, not root or home), + * returning directories or null + * + * @param {string} cwd - Directory to clean + * + * @returns {string[]|null} - Directories to remove + */ function resolveCleanPaths(cwd) { const showWarning = () => { nova.workspace.showWarningMessage( @@ -247,9 +293,12 @@ function resolveCleanPaths(cwd) { return [".zig-cache", "zig-cache", "zig-out"]; } -// Walks up from `startDir` to the nearest ancestor containing `build.zig`, -// stopping at the workspace root. Returns the workspace root if no build.zig -// is found above startDir, or null if no workspace is open. +/** + * Walk up from startDir to find the nearest ancestor containing build.zig, + * stopping at workspace root + * + * @param {string} startDir - Start directory + */ function findNearestZigBuildDir(startDir) { const workspacePath = nova.workspace.path ? nova.path.normalize(nova.workspace.path) @@ -276,6 +325,15 @@ function findNearestZigBuildDir(startDir) { // null when the file is missing, unreadable, or doesn't match the expected // `\.name = "<name>"` / `\.name = .<ident>` shapes. Used to default // `programPath` for the Debug template. + +/** + * Extract the package name from `build.zig.zon` by regex, + * returning null if absent or unreadable + * + * @param {string} cwd - Directory in which to search for build.zig.zon + * + * @returns {string|null} - Package name or null if parsing fails + */ function parseProjectName(cwd) { if (!cwd) return null; const zonPath = nova.path.join(cwd, "build.zig.zon"); @@ -383,6 +441,11 @@ const stepCache = { }, }; +/** + * Resolve the path of the active zig file + * + * @returns {string|null} - Path or null if active editor is not a zig file + */ function activeZigFilePath() { const editor = nova.workspace.activeTextEditor; if (!editor || !editor.document || !editor.document.path) { @@ -396,6 +459,11 @@ function activeZigFilePath() { return editor.document.path; } +/** + * Resolve the directory of the active zig file + * + * @returns {string|null} - Directory or null if active editor is not a zig file + */ function activeZigFileDirectory() { const filePath = activeZigFilePath(); if (!filePath) { @@ -426,6 +494,13 @@ function localizeText(key, fallback, variables) { return text; } +/** + * Wraps Nova's Process API in a Promise, resolving with stdout, stderr, and exit status. + * + * @param {string} command - Absolute path to the executable + * @param {Object} options - Options passed to Nova's Process constructor (args, cwd, env, …) + * @returns {Promise<{status: number, stdout: string, stderr: string}>} + */ function runProcess(command, options) { return new Promise((resolve, reject) => { const stdout = []; @@ -450,6 +525,12 @@ function runProcess(command, options) { }); } +/** + * Find executable on PATH using `which` + * + * @param {string} executableName - Executable name + * @returns {Promise(string|null)} - Path to the executable or null if not found + */ async function findOnPath(executableName) { const result = await runProcess("/usr/bin/env", { args: ["which", executableName], @@ -463,6 +544,13 @@ async function findOnPath(executableName) { return path.length > 0 ? path : null; } +/** + * Resolves an executable path from config first, falling back to PATH search + * + * @param {string} configKey - Configuration key + * @param {string} defaultCommand - Default command to be searched on PATH + * @returns {Promise(string|null)} - Path to the executable or null if not found + */ async function resolveExecutable(configKey, defaultCommand) { const configuredPath = getConfigValue(configKey); if (configuredPath) { @@ -492,7 +580,7 @@ async function resolveZigExecutable() { } /** - * Resolve executable using Xcode xcrun + * Resolve executable using Xcode `xcrun` * * @param {string} executableName - Executable name * @returns {Promise(string|null)} - Path to the executable or null if not found @@ -529,6 +617,10 @@ async function resolveLldbDapExecutable() { return await findOnPath("lldb-dap"); } +/** + * Return Dynamic Linker (DYLD) framework search paths for LLDB + * @returns {string[]} - Search paths + */ function lldbFrameworkPaths() { return [ "/Applications/Xcode-beta.app/Contents/SharedFrameworks/", @@ -537,14 +629,31 @@ function lldbFrameworkPaths() { ]; } +/** + * Return the absolute path to the lldb-dap proxy Perl script bundled + * with the extension + * + * @returns {string} - Path + */ function lldbDapProxyPath() { return nova.path.join(nova.extension.path, "Scripts", "lldb-dap-proxy.pl"); } +/** + * Return the path to the debug adapter log file in extension global storage + * + * @returns {string} - Path + */ function debugAdapterLogPath() { return nova.path.join(nova.extension.globalStoragePath, "lldb-dap-proxy.log"); } +/** + * Return the absolute path to the issue normalizer Perl script bundled + * with the extension + * + * @returns {string} - Path + */ function issueNormalizerScriptPath() { return nova.path.join( nova.extension.path, @@ -553,16 +662,37 @@ function issueNormalizerScriptPath() { ); } +/** + * Wrap a value in single quotes with embedded single quotes escaped, + * safe for POSIX shell + * + * @param {string} value - String + * @returns {string} - Quoted string + */ function quoteShellArgument(value) { const text = value === null || value === undefined ? "" : String(value); return `'${text.replace(/'/g, `'\\''`)}'`; } +/** + * Escape backslashes and double quotes for safe embedding in AppleScript + * + * @param {string} value - String + * @returns {string} - Escaped string + */ function escapeAppleScriptString(value) { const text = value === null || value === undefined ? "" : String(value); return text.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); } +/** + * Build a safe shell command string with cd preamble + * + * @param {string} command - Command + * @param {string[]} args - Arguments + * @param {string} cwd - Working directory + * @returns {string} - Safe shell command + */ function buildShellCommand(command, args, cwd) { const segments = []; if (cwd) { @@ -577,6 +707,13 @@ function buildShellCommand(command, args, cwd) { return segments.join("; "); } +/** + * Build a shell command that pipes zig output through the issue normalizer + * + * @param {string} command - Command + * @param {string[]} args - Arguments + * @returns {string} - Piped command + */ function buildIssueNormalizedCommand(command, args) { const commandLine = [ quoteShellArgument(command), @@ -586,6 +723,11 @@ function buildIssueNormalizedCommand(command, args) { return `setopt pipefail; ${commandLine} 2>&1 | ${rewriter}`; } +/** + * Open macOS Terminal and run a shell command via AppleScript + * + * @param {string} commandLine - Command to run + */ function launchInTerminal(commandLine) { return new Promise((resolve) => { const script = `tell application "Terminal" |
