import { get } from 'svelte/store'; import type { ModalSettings, ModalStore } from '@skeletonlabs/skeleton'; import { pathTemplate } from './pathTemplate'; import type { OpenAPIV3_1 } from './openAPITypes'; import { selectedSpec } from './db'; export const pathVariables = /\{([^}]+)\}/gm; export const pathRegex = /\/([/]*[{]?[a-zA-Z]+[}]?)*/gm; /// Adds a new path to the OpenAPI document export const addPath = (modalStore: ModalStore, startingPoint: string = '/') => { let userPath: string = startingPoint.trim(); const modal: ModalSettings = { type: 'prompt', // Data title: 'Enter Pathname', body: 'Wrap path parameters in curly braces. Example: /users/{userId}', // Populates the input value and attributes value: userPath, valueAttr: { type: 'text', minlength: 1, required: true }, // Returns the updated response value response: (r: string | boolean | undefined) => { if (r === false) return; if (typeof r !== 'string') return; userPath = r; // Check if path already exists if (!pathExists(userPath)) { alert('Path already exists'); return; } // Check if path is valid if (!isValidPath(userPath)) { alert('Invalid path'); return; } // create path object const store = get(selectedSpec); if (!store.spec.paths) store.spec.paths = {}; store.spec.paths[userPath] = pathTemplate; // sort paths alphabetically sortPathsAlphabetically(); } }; modalStore.trigger(modal); }; export const renamePath = (modalStore: ModalStore, oldPath: string) => { let userPath: string = oldPath; const modal: ModalSettings = { type: 'prompt', // Data title: 'Rename path', body: 'Wrap path parameters in curly braces. Example: /users/{userId}', // Populates the input value and attributes value: userPath, valueAttr: { type: 'text', minlength: 1, required: true }, // Returns the updated response value response: (r: string | boolean | undefined) => { if (r === false) return; if (typeof r !== 'string') return; userPath = r; // Check if path already exists if (!pathExists(userPath)) { alert('Path already exists'); return; } // Check if path is valid if (!isValidPath(userPath)) { alert('Invalid path'); return; } // create path object const store = get(selectedSpec); if (!store.spec.paths) store.spec.paths = {}; // copy old path object to new path object store.spec.paths[userPath] = store.spec.paths[oldPath]; // delete old path object delete store.spec.paths[oldPath]; // add path to store selectedSpec.set(store); // sort paths alphabetically sortPathsAlphabetically(); } }; modalStore.trigger(modal); }; /// Removes a path from the OpenAPI document export const deletePath = (modalStore: ModalStore, path: string) => { const modal: ModalSettings = { type: 'confirm', // Data title: `Delete ${path}?`, body: 'Are you sure you wish to delete the path?', // TRUE if confirm pressed, FALSE if cancel pressed response: (r: boolean) => { if (r === false) return; const store = get(selectedSpec); // check if path exists if (!store.spec.paths) return; if (!(path in store.spec.paths)) return; delete store.spec.paths[path]; selectedSpec.set(store); } }; modalStore.trigger(modal); }; /// checks if a given path already exists export const pathExists = (path: string) => { const store = get(selectedSpec); return !(path in store.spec.paths!); }; /// checks if a given path is valid export const isValidPath = (path: string) => { // check if path variables aren't duplicated const variableRegex = /\{([^}]+)\}/gm; const variables = path.match(variableRegex); if (variables) { const uniqueVariables = new Set(variables); if (variables.length !== uniqueVariables.size) return false; } // check if path is a valid path const pathWithoutVariables = path.replaceAll('{', '').replaceAll('}', ''); console.log(pathWithoutVariables); const pathRegex = /(\/[a-zA-Z0-9]+)+|\//gm; const pathParts = pathWithoutVariables.match(pathRegex); // the fallback is to return false if the pathParts array is null return pathParts?.length === 1; }; /// sorts the paths in the OpenAPI document alphabetically export const sortPathsAlphabetically = () => { const tempPathObject = {}; const store = get(selectedSpec); // @ts-expect-error - we are working with an initially empty object Object.keys(store.spec.paths) .sort() .forEach((key) => { // @ts-expect-error - we are working with initially empty objects tempPathObject[key] = store.spec.paths[key]; }); // update path object selectedSpec.update((data) => { data.spec.paths = tempPathObject; return data; }); }; export const getPathVariables = (path: string) => { const variables = path.match(pathVariables); if (!variables) return []; return variables.map((variable) => variable.replace('{', '').replace('}', '')); }; export const sortPathParameters = (parameters: OpenAPIV3_1.ParameterObject[]) => { const tempParameters = parameters; tempParameters.sort((a, b) => { if (a.in < b.in) return -1; if (a.in > b.in) return 1; return 0; }); return tempParameters; };