UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

273 lines 9.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.completePath = void 0; class StepManager { constructor() { this.step = new Step(); } addEntry(item) { let owningStep = this.step; for (let partIndex in item.parts.slice(0, -1)) { const part = item.parts[partIndex]; const hasEntry = owningStep.entries.find((i) => i.name === part); if (hasEntry) { if (!hasEntry.nextStep) { hasEntry.addStep(); } owningStep = hasEntry.nextStep; continue; } const newEntry = new Entry(part, [], true); owningStep.entries.push(newEntry); owningStep = newEntry.nextStep; } const entry = new Entry(item.parts.pop(), item.methods); owningStep.entries.push(entry); return; } getPathsForEntry(userInput, entry, method) { let step = this.step; const inputs = userInput.split('/').filter(Boolean); if (userInput.endsWith('/')) { inputs.push('/'); } let path = '/'; for (let input of inputs.slice(0, -1)) { let currentEntry = step.entries.find(e => e.name === input); if (!currentEntry && step.hasParameter) { currentEntry = step.parameter; path += input; } else if (currentEntry) { path += currentEntry.name; } path += '/'; if (!currentEntry || !currentEntry.nextStep) { throw new Error('Invalid path for entry, path was: ' + path); } step = currentEntry.nextStep; } const lastPart = inputs.pop(); if (lastPart === entry.name) { if (entry.isEndpoint) { return []; } if (entry.hasFollowingPath) { if (entry.nextStep.hasParameter) { return []; } if (entry.nextStep.entries.length === 1) { return [ userInput + '/' + entry.nextStep.entries[0].name, userInput + '/' + entry.nextStep.entries[0].name + '/' ]; } return []; } } const result = []; if (entry.isEndpoint) { if (entry.methods.includes(method)) { result.push(path + entry.name); } if (entry.hasFollowingPath) { result.push(path + entry.name + '/'); } return result; } if (entry.hasFollowingPath) { if (entry.nextStep.guessable !== 'yes') { result.push(path + entry.name + '/'); return result; } for (let nextEntry of entry.nextStep.entries) { if (nextEntry.isEndpoint) { result.push(path + entry.name + '/' + nextEntry.name); } if (nextEntry.hasFollowingPath) { result.push(path + entry.name + '/' + nextEntry.name + '/'); } } } return result; } } class Step { constructor() { this.entries = []; } get guessable() { const hasParam = this.entries.some((i) => i.isParameter); const hasNonParam = this.entries.some((i) => !i.isParameter); if (hasParam && hasNonParam) { return 'maybe'; } if (hasParam) { return 'no'; } return 'yes'; } get hasParameter() { return this.entries.some(e => e.isParameter); } get parameter() { return this.entries.find(e => e.isParameter); } validEntriesForMethod(method) { return this.entries.filter(e => e.validForMethod(method)); } } class Entry { constructor(name, methods, addStep) { this.name = name; this.methods = methods; if (addStep) { this.addStep(); } } get hasFollowingPath() { return !!this.nextStep; } get isParameter() { return this.name.startsWith(':'); } get isEndpoint() { return this.methods.length > 0; } addStep() { this.nextStep = new Step(); } validForMethod(method) { if (!this.nextStep) { return this.methods.includes(method); } if (this.methods.includes(method)) { return true; } for (let entry of this.nextStep.entries) { const entryIsValid = entry.validForMethod(method); if (entryIsValid) { return true; } } return false; } } function generateResourceMap(rawMap) { const stepManager = new StepManager(); const mapItems = rawMap .map((i) => ({ parts: i.path.split('/').filter(Boolean), methods: i.supports })) .sort((a, b) => a.parts.length - b.parts.length); for (let item of mapItems) { stepManager.addEntry(item); } return stepManager; } function completePath(input, method, rawMap) { if (!input.startsWith('/')) { return []; } const inputs = input.split('/').filter(Boolean); if (input.endsWith('/')) { inputs.push(''); } let stepManager = generateResourceMap(rawMap); let step = stepManager.step; // If user inputs only / character, split returns empty array, // so we return each possibility if (inputs.length < 1) { const completions = []; step.validEntriesForMethod(method) .forEach((e) => { if (e.isEndpoint && e.methods.includes(method)) { completions.push(`/${e.name}`); } if (e.hasFollowingPath) { completions.push(`/${e.name}/`); } }); if (completions.length === 1) { if (completions[0].endsWith('/')) { completions.push(completions[0].slice(0, -1)); } else { completions.push(completions[0] + '/'); } } return completions; } const completionEntries = []; // We go through each part of user input for (let inputIndex in inputs) { const inputForStep = inputs[inputIndex]; // if user input is not valid within the resource map, return | (A) if (!step) { return []; } // if not at last part of input - ex: /org/coke - coke is the last part // Lower step if (parseInt(inputIndex) < inputs.length - 1) { let lowerStepEntry = step.entries.find((i) => i.name === inputForStep); // if not found with input, and this step has a parameter entry if (!lowerStepEntry && step.hasParameter) { lowerStepEntry = step.entries.find((i) => i.isParameter); } // if no parameter entry found, then it means input is invalid, so we return empty if (!lowerStepEntry) { return []; } // We made all the check with this part of input, we go one step up in the hierarchy and finish the iteration step = lowerStepEntry.nextStep; continue; } // Current step of input else if (parseInt(inputIndex) === inputs.length - 1) { let currentStepEntry = step.entries.find((i) => i.name === inputForStep); if (currentStepEntry) { if (currentStepEntry.isEndpoint) { return []; } if (currentStepEntry.hasFollowingPath) { return stepManager.getPathsForEntry(input, currentStepEntry, method).flat(); } return []; } if (step.guessable === 'no') { return []; } if (step.guessable === 'yes') { step.validEntriesForMethod(method) .filter(e => e.name.startsWith(inputForStep)) .forEach(e => { completionEntries.push(e); }); break; } // step.guessable is 'maybe' if (!inputForStep.startsWith('-')) { return []; } step.validEntriesForMethod(method) .filter((i) => i.name.startsWith(inputForStep)) .forEach((e) => { completionEntries.push(e); }); break; } } if (completionEntries.length === 1) { const singleResultArray = []; const singleResult = completionEntries.map(e => stepManager.getPathsForEntry(input, e, method)).flat()[0]; singleResultArray.push(singleResult); if (singleResult.endsWith('/')) { singleResultArray.push(singleResult.slice(0, -1)); } else { singleResultArray.push(singleResult + '/'); } return singleResultArray; } return completionEntries.map(e => stepManager.getPathsForEntry(input, e, method)).flat(); } exports.completePath = completePath; //# sourceMappingURL=resourceMapGenerator.js.map