aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Czihak <git@dcz.at>2026-05-08 21:15:49 +0200
committerDavid Czihak <git@dcz.at>2026-05-08 21:15:49 +0200
commit31ef0db515770896f5708aeeadadb211ccf3d3b3 (patch)
treee233f78275932b81ae3c57965c53bb1b016373f5
parent8ddd84baba48df6c146f2d15fd017d7928473d41 (diff)
Docs: Add JSDoc comments to utility functions
-rw-r--r--Scripts/main.js154
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"