UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

135 lines (134 loc) 5.1 kB
"use strict"; // Command dispatcher Object.defineProperty(exports, "__esModule", { value: true }); exports.finder = void 0; const path = require("path"); const fs = require("fs"); const util_1 = require("util"); const debug = require("debug")("appcenter-cli:util:commandline:command-finder"); // Helpers for file system checks function toFullPath(dispatchRoot, pathParts) { return path.join.apply(null, [dispatchRoot].concat(pathParts)); } function checkStats(dispatchRoot, pathParts, check) { try { const filePath = toFullPath(dispatchRoot, pathParts); debug(`Checking stats for ${filePath}`); const stats = fs.statSync(filePath); return check(stats); } catch (err) { if (err.code === "ENOENT") { return false; } throw err; } } function stripExtension(name) { const extLen = path.extname(name).length; if (extLen > 0) { return name.slice(0, -extLen); } return name; } function isDir(dispatchRoot, pathParts) { return checkStats(dispatchRoot, pathParts, (s) => s.isDirectory()); } function normalizeCommandNames(command) { return command.map((part) => part.toLowerCase()); } const legalCommandRegex = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/; function isLegalCommandName(commandName) { debug(`Checking legality of '${commandName}'`); return legalCommandRegex.test(commandName) && commandName !== "lib"; } function splitCommandLine(command) { let partitionPoint = command.findIndex((cmd) => !isLegalCommandName(cmd)); if (partitionPoint === -1) { partitionPoint = command.length; } return [command.slice(0, partitionPoint), command.slice(partitionPoint)]; } // Helper functions to construct results function commandNotFound(commandParts) { debug(`No command found at '${commandParts.join(" ")}'`); return { found: false, isCategory: false, commandPath: null, commandParts, unusedArgs: [], }; } function commandFound(commandPath, commandParts, unusedArgs) { debug(`Command '${commandParts.join(" ")}' found at ${commandPath}`); return { found: true, isCategory: false, commandPath, commandParts: commandParts.map(stripExtension), unusedArgs, }; } function categoryFound(commandPath, commandParts, unusedArgs) { debug(`Category '${commandParts.join(" ")}' found at ${commandPath}`); return { found: true, isCategory: true, commandPath, commandParts, unusedArgs, }; } function finder(dispatchRoot) { if (!isDir(dispatchRoot, [])) { throw new Error("Invalid dispatch root"); } return function commandFinder(commandLineArgs) { debug(`Looking for command ${util_1.inspect(commandLineArgs)}`); const [command, args] = splitCommandLine(commandLineArgs); if (command.length === 0) { return categoryFound(toFullPath(dispatchRoot, []), [], commandLineArgs); } function findFile(commandDir, commandName) { debug(`Looking for '${commandName}' in directory '${toFullPath(dispatchRoot, commandDir)}'`); if (commandDir.length > 0 && !isDir(dispatchRoot, commandDir)) { return null; } const fullCommand = commandDir.concat([commandName]); if (checkStats(dispatchRoot, fullCommand, (stats) => stats.isDirectory())) { return [toFullPath(dispatchRoot, fullCommand), fullCommand, false]; } // Have to look through the directory so that we // can ignore any potential file extensions. const files = fs.readdirSync(toFullPath(dispatchRoot, commandDir)); const matching = files.filter((file) => path.parse(file).name === commandName); if (matching.length > 1) { throw new Error(`Ambiguous match for command '${commandLineArgs.join(" ")}'`); } if (matching.length === 0) { return null; } const commandParts = commandDir.concat([matching[0]]); const commandPath = toFullPath(dispatchRoot, commandDir.concat([matching[0]])); return [commandPath, commandParts, true]; } while (command.length > 0) { const commandName = normalizeCommandNames(command.slice(-1))[0]; const commandDir = normalizeCommandNames(command.slice(0, -1)); const result = findFile(commandDir, commandName); if (result !== null) { if (result[2]) { return commandFound(result[0], result[1], args); } return categoryFound(result[0], result[1], args); } // Not found, push the last arg in command name into unused pile. args.unshift(command.pop()); debug(`Not found, unused args = ${args}, new command = ${command}`); } // Got here, nothing found return commandNotFound(commandLineArgs); }; } exports.finder = finder;