mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-15 20:01:28 +00:00
workspace schema update (#6374)
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
const { dialog, ipcMain } = require('electron');
|
||||
const { isDirectory, normalizeAndResolvePath } = require('../utils/filesystem');
|
||||
const { normalizeAndResolvePath } = require('../utils/filesystem');
|
||||
const { generateUidBasedOnHash } = require('../utils/common');
|
||||
const { generateYamlContent } = require('../utils/workspace-config');
|
||||
|
||||
const normalizeWorkspaceConfig = (config) => {
|
||||
return {
|
||||
...config,
|
||||
name: config.info?.name,
|
||||
type: config.info?.type,
|
||||
collections: config.collections || [],
|
||||
apiSpecs: config.specs || []
|
||||
};
|
||||
};
|
||||
|
||||
const openApiSpecDialog = async (win, watcher, options = {}) => {
|
||||
const { filePaths } = await dialog.showOpenDialog(win, {
|
||||
@@ -32,7 +43,7 @@ const openApiSpec = async (win, watcher, apiSpecPath, options = {}) => {
|
||||
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
|
||||
const workspaceConfig = yaml.load(yamlContent);
|
||||
|
||||
workspaceConfig.apiSpecs = workspaceConfig.apiSpecs || [];
|
||||
const specs = workspaceConfig.specs || [];
|
||||
|
||||
let relativePath = apiSpecPath;
|
||||
try {
|
||||
@@ -44,32 +55,28 @@ const openApiSpec = async (win, watcher, apiSpecPath, options = {}) => {
|
||||
console.log('Using absolute path for API spec:', error.message);
|
||||
}
|
||||
|
||||
const apiSpecName = path.basename(apiSpecPath, path.extname(apiSpecPath));
|
||||
const apiSpecEntry = {
|
||||
name: apiSpecName,
|
||||
const specName = path.basename(apiSpecPath, path.extname(apiSpecPath));
|
||||
const specEntry = {
|
||||
name: specName,
|
||||
path: relativePath
|
||||
};
|
||||
|
||||
const existingApiSpec = workspaceConfig.apiSpecs.find((a) => {
|
||||
const existingSpec = specs.find((a) => {
|
||||
const existingPath = path.isAbsolute(a.path)
|
||||
? a.path
|
||||
: path.resolve(options.workspacePath, a.path);
|
||||
return existingPath === apiSpecPath || a.name === apiSpecName;
|
||||
return existingPath === apiSpecPath || a.name === specName;
|
||||
});
|
||||
|
||||
if (!existingApiSpec) {
|
||||
workspaceConfig.apiSpecs.push(apiSpecEntry);
|
||||
if (!existingSpec) {
|
||||
workspaceConfig.specs = [...specs, specEntry];
|
||||
|
||||
const updatedYamlContent = yaml.dump(workspaceConfig, {
|
||||
indent: 2,
|
||||
lineWidth: -1,
|
||||
noRefs: true
|
||||
});
|
||||
const updatedYamlContent = generateYamlContent(workspaceConfig);
|
||||
fs.writeFileSync(workspaceFilePath, updatedYamlContent);
|
||||
|
||||
// Notify frontend that workspace config was updated
|
||||
const normalizedConfig = normalizeWorkspaceConfig(workspaceConfig);
|
||||
const workspaceUid = generateUidBasedOnHash(options.workspacePath);
|
||||
win.webContents.send('main:workspace-config-updated', options.workspacePath, workspaceUid, workspaceConfig);
|
||||
win.webContents.send('main:workspace-config-updated', options.workspacePath, workspaceUid, normalizedConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,17 +10,21 @@ const { decryptStringSafe } = require('../utils/encryption');
|
||||
|
||||
const environmentSecretsStore = new EnvironmentSecretsStore();
|
||||
|
||||
/**
|
||||
* Check if environment has secret variables
|
||||
*/
|
||||
const envHasSecrets = (environment) => {
|
||||
const secrets = _.filter(environment.variables, (v) => v.secret === true);
|
||||
return secrets && secrets.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle workspace.yml file changes
|
||||
*/
|
||||
const normalizeWorkspaceConfig = (config) => {
|
||||
return {
|
||||
...config,
|
||||
name: config.info?.name,
|
||||
type: config.info?.type,
|
||||
collections: config.collections || [],
|
||||
apiSpecs: config.specs || []
|
||||
};
|
||||
};
|
||||
|
||||
const handleWorkspaceFileChange = (win, workspacePath) => {
|
||||
try {
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
@@ -30,9 +34,11 @@ const handleWorkspaceFileChange = (win, workspacePath) => {
|
||||
}
|
||||
|
||||
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
|
||||
const workspaceConfig = yaml.load(yamlContent);
|
||||
const rawConfig = yaml.load(yamlContent);
|
||||
const workspaceConfig = normalizeWorkspaceConfig(rawConfig);
|
||||
|
||||
if (workspaceConfig.type !== 'workspace') {
|
||||
const type = workspaceConfig.info?.type || workspaceConfig.type;
|
||||
if (type !== 'workspace') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,9 +50,6 @@ const handleWorkspaceFileChange = (win, workspacePath) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse global environment file and handle secrets
|
||||
*/
|
||||
const parseGlobalEnvironmentFile = async (pathname, workspacePath, workspaceUid) => {
|
||||
const basename = path.basename(pathname);
|
||||
const environmentName = basename.slice(0, -'.yml'.length);
|
||||
@@ -64,14 +67,12 @@ const parseGlobalEnvironmentFile = async (pathname, workspacePath, workspaceUid)
|
||||
file.data.name = environmentName;
|
||||
file.data.uid = generateUidBasedOnHash(pathname);
|
||||
|
||||
// Ensure all variables have UIDs
|
||||
_.each(_.get(file, 'data.variables', []), (variable) => {
|
||||
if (!variable.uid) {
|
||||
variable.uid = uuid();
|
||||
}
|
||||
});
|
||||
|
||||
// Decrypt secrets if present
|
||||
if (envHasSecrets(file.data)) {
|
||||
const envSecrets = environmentSecretsStore.getEnvSecrets(workspacePath, file.data);
|
||||
_.each(envSecrets, (secret) => {
|
||||
@@ -86,9 +87,6 @@ const parseGlobalEnvironmentFile = async (pathname, workspacePath, workspaceUid)
|
||||
return file;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle global environment file add
|
||||
*/
|
||||
const handleGlobalEnvironmentFileAdd = async (win, pathname, workspacePath, workspaceUid) => {
|
||||
try {
|
||||
const file = await parseGlobalEnvironmentFile(pathname, workspacePath, workspaceUid);
|
||||
@@ -98,9 +96,6 @@ const handleGlobalEnvironmentFileAdd = async (win, pathname, workspacePath, work
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle global environment file change
|
||||
*/
|
||||
const handleGlobalEnvironmentFileChange = async (win, pathname, workspacePath, workspaceUid) => {
|
||||
try {
|
||||
const file = await parseGlobalEnvironmentFile(pathname, workspacePath, workspaceUid);
|
||||
@@ -110,9 +105,6 @@ const handleGlobalEnvironmentFileChange = async (win, pathname, workspacePath, w
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle global environment file unlink
|
||||
*/
|
||||
const handleGlobalEnvironmentFileUnlink = async (win, pathname, workspaceUid) => {
|
||||
try {
|
||||
const environmentUid = generateUidBasedOnHash(pathname);
|
||||
@@ -122,10 +114,6 @@ const handleGlobalEnvironmentFileUnlink = async (win, pathname, workspaceUid) =>
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Workspace Watcher
|
||||
* Watches workspace files for changes and notifies the renderer
|
||||
*/
|
||||
class WorkspaceWatcher {
|
||||
constructor() {
|
||||
this.watchers = {};
|
||||
@@ -137,7 +125,6 @@ class WorkspaceWatcher {
|
||||
const environmentsDir = path.join(workspacePath, 'environments');
|
||||
const workspaceUid = generateUidBasedOnHash(workspacePath);
|
||||
|
||||
// Close existing watchers if any
|
||||
if (this.watchers[workspacePath]) {
|
||||
this.watchers[workspacePath].close();
|
||||
}
|
||||
@@ -147,12 +134,10 @@ class WorkspaceWatcher {
|
||||
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
// Guard against window being destroyed during delay
|
||||
if (win.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch workspace.yml file
|
||||
const watcher = chokidar.watch(workspaceFilePath, {
|
||||
ignoreInitial: false,
|
||||
persistent: true,
|
||||
@@ -168,7 +153,6 @@ class WorkspaceWatcher {
|
||||
|
||||
self.watchers[workspacePath] = watcher;
|
||||
|
||||
// Watch global environment files (.yml)
|
||||
if (fs.existsSync(environmentsDir)) {
|
||||
const envWatcher = chokidar.watch(path.join(environmentsDir, `*.yml`), {
|
||||
ignoreInitial: true,
|
||||
@@ -194,7 +178,6 @@ class WorkspaceWatcher {
|
||||
|
||||
self.environmentWatchers[workspacePath] = envWatcher;
|
||||
} else {
|
||||
// Watch for environments directory creation
|
||||
const dirWatcher = chokidar.watch(environmentsDir, {
|
||||
ignoreInitial: false,
|
||||
persistent: true,
|
||||
|
||||
@@ -2,8 +2,10 @@ const { ipcMain } = require('electron');
|
||||
const { openApiSpecDialog, openApiSpec } = require('../app/apiSpecs');
|
||||
const { writeFile } = require('../utils/filesystem');
|
||||
const { removeApiSpecUid } = require('../cache/apiSpecUids');
|
||||
const { generateYamlContent } = require('../utils/workspace-config');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedApiSpecs) => {
|
||||
ipcMain.handle('renderer:open-api-spec', (event, workspacePath = null) => {
|
||||
@@ -47,32 +49,29 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedApiSpecs)
|
||||
removeApiSpecUid(pathname);
|
||||
|
||||
if (workspacePath) {
|
||||
const yaml = require('js-yaml');
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
|
||||
if (fs.existsSync(workspaceFilePath)) {
|
||||
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
|
||||
const workspaceConfig = yaml.load(yamlContent);
|
||||
|
||||
if (workspaceConfig.apiSpecs) {
|
||||
workspaceConfig.apiSpecs = workspaceConfig.apiSpecs.filter((a) => {
|
||||
const apiSpecPathFromYml = a.path;
|
||||
if (!apiSpecPathFromYml) return true;
|
||||
const specs = workspaceConfig.specs || [];
|
||||
|
||||
const absoluteApiSpecPath = path.isAbsolute(apiSpecPathFromYml)
|
||||
? apiSpecPathFromYml
|
||||
: path.resolve(workspacePath, apiSpecPathFromYml);
|
||||
const filteredSpecs = specs.filter((a) => {
|
||||
const specPathFromYml = a.path;
|
||||
if (!specPathFromYml) return true;
|
||||
|
||||
return absoluteApiSpecPath !== pathname;
|
||||
});
|
||||
const absoluteSpecPath = path.isAbsolute(specPathFromYml)
|
||||
? specPathFromYml
|
||||
: path.resolve(workspacePath, specPathFromYml);
|
||||
|
||||
const updatedYamlContent = yaml.dump(workspaceConfig, {
|
||||
indent: 2,
|
||||
lineWidth: -1,
|
||||
noRefs: true
|
||||
});
|
||||
fs.writeFileSync(workspaceFilePath, updatedYamlContent);
|
||||
}
|
||||
return absoluteSpecPath !== pathname;
|
||||
});
|
||||
|
||||
workspaceConfig.specs = filteredSpecs;
|
||||
|
||||
const updatedYamlContent = generateYamlContent(workspaceConfig);
|
||||
fs.writeFileSync(workspaceFilePath, updatedYamlContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,19 +169,19 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
const apiSpecs = workspaceConfig.apiSpecs || [];
|
||||
const specs = workspaceConfig.specs || [];
|
||||
|
||||
const resolvedApiSpecs = apiSpecs.map((apiSpec) => {
|
||||
if (apiSpec.path && !path.isAbsolute(apiSpec.path)) {
|
||||
const resolvedSpecs = specs.map((spec) => {
|
||||
if (spec.path && !path.isAbsolute(spec.path)) {
|
||||
return {
|
||||
...apiSpec,
|
||||
path: path.join(workspacePath, apiSpec.path)
|
||||
...spec,
|
||||
path: path.join(workspacePath, spec.path)
|
||||
};
|
||||
}
|
||||
return apiSpec;
|
||||
return spec;
|
||||
});
|
||||
|
||||
return resolvedApiSpecs;
|
||||
return resolvedSpecs;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { app } = require('electron');
|
||||
const yaml = require('js-yaml');
|
||||
const { generateUidBasedOnHash } = require('../utils/common');
|
||||
const { writeFile, createDirectory } = require('../utils/filesystem');
|
||||
const { getPreferences, savePreferences } = require('./preferences');
|
||||
const { globalEnvironmentsStore } = require('./global-environments');
|
||||
const { generateYamlContent } = require('../utils/workspace-config');
|
||||
|
||||
const OPENCOLLECTION_VERSION = '1.0.0';
|
||||
|
||||
class DefaultWorkspaceManager {
|
||||
constructor() {
|
||||
@@ -112,22 +114,21 @@ class DefaultWorkspaceManager {
|
||||
await createDirectory(path.join(workspacePath, 'environments'));
|
||||
|
||||
const workspaceConfig = {
|
||||
name: 'My Workspace',
|
||||
type: 'default',
|
||||
version: '1.0.0',
|
||||
docs: '',
|
||||
collections: []
|
||||
opencollection: OPENCOLLECTION_VERSION,
|
||||
info: {
|
||||
name: 'My Workspace',
|
||||
type: 'default'
|
||||
},
|
||||
collections: [],
|
||||
specs: [],
|
||||
docs: ''
|
||||
};
|
||||
|
||||
if (migrateFromPreferences) {
|
||||
await this.migrateFromPreferences(workspacePath, workspaceConfig);
|
||||
}
|
||||
|
||||
const yamlContent = yaml.dump(workspaceConfig, {
|
||||
indent: 2,
|
||||
lineWidth: -1,
|
||||
noRefs: true
|
||||
});
|
||||
const yamlContent = generateYamlContent(workspaceConfig);
|
||||
await writeFile(path.join(workspacePath, 'workspace.yml'), yamlContent);
|
||||
|
||||
await this.setDefaultWorkspacePath(workspacePath);
|
||||
|
||||
@@ -7,6 +7,7 @@ const { writeFile, createDirectory } = require('../utils/filesystem');
|
||||
const { generateUidBasedOnHash, uuid } = require('../utils/common');
|
||||
const { decryptStringSafe } = require('../utils/encryption');
|
||||
const EnvironmentSecretsStore = require('./env-secrets');
|
||||
const { generateYamlContent } = require('../utils/workspace-config');
|
||||
|
||||
const environmentSecretsStore = new EnvironmentSecretsStore();
|
||||
|
||||
@@ -162,11 +163,7 @@ class GlobalEnvironmentsManager {
|
||||
|
||||
workspaceConfig.activeEnvironmentUid = environmentUid;
|
||||
|
||||
const yamlOutput = yaml.dump(workspaceConfig, {
|
||||
indent: 2,
|
||||
lineWidth: -1,
|
||||
noRefs: true
|
||||
});
|
||||
const yamlOutput = generateYamlContent(workspaceConfig);
|
||||
|
||||
await writeFile(workspaceFilePath, yamlOutput);
|
||||
return true;
|
||||
|
||||
@@ -4,6 +4,7 @@ const yaml = require('js-yaml');
|
||||
const { writeFile, validateName } = require('./filesystem');
|
||||
|
||||
const WORKSPACE_TYPE = 'workspace';
|
||||
const OPENCOLLECTION_VERSION = '1.0.0';
|
||||
|
||||
const makeRelativePath = (workspacePath, absolutePath) => {
|
||||
if (!path.isAbsolute(absolutePath)) {
|
||||
@@ -61,14 +62,26 @@ const validateWorkspaceDirectory = (dirPath) => {
|
||||
};
|
||||
|
||||
const createWorkspaceConfig = (workspaceName) => ({
|
||||
name: workspaceName,
|
||||
type: WORKSPACE_TYPE,
|
||||
version: '1.0.0',
|
||||
docs: '',
|
||||
opencollection: OPENCOLLECTION_VERSION,
|
||||
info: {
|
||||
name: workspaceName,
|
||||
type: WORKSPACE_TYPE
|
||||
},
|
||||
collections: [],
|
||||
apiSpecs: []
|
||||
specs: [],
|
||||
docs: ''
|
||||
});
|
||||
|
||||
const normalizeWorkspaceConfig = (config) => {
|
||||
return {
|
||||
...config,
|
||||
name: config.info?.name,
|
||||
type: config.info?.type,
|
||||
collections: config.collections || [],
|
||||
apiSpecs: config.specs || []
|
||||
};
|
||||
};
|
||||
|
||||
const readWorkspaceConfig = (workspacePath) => {
|
||||
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
|
||||
|
||||
@@ -83,15 +96,69 @@ const readWorkspaceConfig = (workspacePath) => {
|
||||
throw new Error('Invalid workspace: workspace.yml is malformed');
|
||||
}
|
||||
|
||||
return workspaceConfig;
|
||||
return normalizeWorkspaceConfig(workspaceConfig);
|
||||
};
|
||||
|
||||
const generateYamlContent = (config) => {
|
||||
const yamlLines = [];
|
||||
yamlLines.push(`opencollection: ${config.opencollection || OPENCOLLECTION_VERSION}`);
|
||||
yamlLines.push('info:');
|
||||
yamlLines.push(` name: ${config.info?.name || config.name}`);
|
||||
yamlLines.push(` type: ${config.info?.type || config.type || WORKSPACE_TYPE}`);
|
||||
yamlLines.push('');
|
||||
|
||||
const collections = config.collections || [];
|
||||
if (collections.length > 0) {
|
||||
yamlLines.push('collections:');
|
||||
for (const collection of collections) {
|
||||
yamlLines.push(` - name: ${collection.name}`);
|
||||
yamlLines.push(` path: ${collection.path}`);
|
||||
if (collection.remote) {
|
||||
yamlLines.push(` remote: ${collection.remote}`);
|
||||
}
|
||||
if (collection.type) {
|
||||
yamlLines.push(` type: ${collection.type}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yamlLines.push('collections:');
|
||||
}
|
||||
yamlLines.push('');
|
||||
|
||||
const specs = config.specs || [];
|
||||
if (specs.length > 0) {
|
||||
yamlLines.push('specs:');
|
||||
for (const spec of specs) {
|
||||
yamlLines.push(` - name: ${spec.name}`);
|
||||
yamlLines.push(` path: ${spec.path}`);
|
||||
}
|
||||
} else {
|
||||
yamlLines.push('specs:');
|
||||
}
|
||||
yamlLines.push('');
|
||||
|
||||
const docs = config.docs || '';
|
||||
if (docs) {
|
||||
const escapedDocs = docs.includes('\n')
|
||||
? `|-\n ${docs.split('\n').join('\n ')}`
|
||||
: `'${docs.replace(/'/g, '\'\'')}'`;
|
||||
yamlLines.push(`docs: ${escapedDocs}`);
|
||||
} else {
|
||||
yamlLines.push('docs: \'\'');
|
||||
}
|
||||
|
||||
if (config.activeEnvironmentUid) {
|
||||
yamlLines.push('');
|
||||
yamlLines.push(`activeEnvironmentUid: ${config.activeEnvironmentUid}`);
|
||||
}
|
||||
|
||||
yamlLines.push('');
|
||||
|
||||
return yamlLines.join('\n');
|
||||
};
|
||||
|
||||
const writeWorkspaceConfig = async (workspacePath, config) => {
|
||||
const yamlContent = yaml.dump(config, {
|
||||
indent: 2,
|
||||
lineWidth: -1,
|
||||
noRefs: true
|
||||
});
|
||||
const yamlContent = generateYamlContent(config);
|
||||
await writeFile(path.join(workspacePath, 'workspace.yml'), yamlContent);
|
||||
};
|
||||
|
||||
@@ -100,11 +167,13 @@ const validateWorkspaceConfig = (config) => {
|
||||
throw new Error('Workspace configuration must be an object');
|
||||
}
|
||||
|
||||
if (config.type !== WORKSPACE_TYPE) {
|
||||
const type = config.info?.type || config.type;
|
||||
if (type !== WORKSPACE_TYPE) {
|
||||
throw new Error('Invalid workspace: not a bruno workspace');
|
||||
}
|
||||
|
||||
if (!config.name || typeof config.name !== 'string') {
|
||||
const name = config.info?.name || config.name;
|
||||
if (!name || typeof name !== 'string') {
|
||||
throw new Error('Workspace must have a valid name');
|
||||
}
|
||||
|
||||
@@ -114,6 +183,9 @@ const validateWorkspaceConfig = (config) => {
|
||||
const updateWorkspaceName = async (workspacePath, newName) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
config.name = newName;
|
||||
if (config.info) {
|
||||
config.info.name = newName;
|
||||
}
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
return config;
|
||||
};
|
||||
@@ -132,7 +204,6 @@ const addCollectionToWorkspace = async (workspacePath, collection) => {
|
||||
config.collections = [];
|
||||
}
|
||||
|
||||
// Normalize collection entry
|
||||
const normalizedCollection = {
|
||||
name: collection.name,
|
||||
path: collection.path
|
||||
@@ -142,7 +213,6 @@ const addCollectionToWorkspace = async (workspacePath, collection) => {
|
||||
normalizedCollection.remote = collection.remote;
|
||||
}
|
||||
|
||||
// Check if collection already exists
|
||||
const existingIndex = config.collections.findIndex((c) => c.name === normalizedCollection.name || c.path === normalizedCollection.path);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
@@ -168,7 +238,6 @@ const removeCollectionFromWorkspace = async (workspacePath, collectionPath) => {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert to absolute path for comparison
|
||||
const absoluteCollectionPath = path.isAbsolute(collectionPathFromYml)
|
||||
? collectionPathFromYml
|
||||
: path.resolve(workspacePath, collectionPathFromYml);
|
||||
@@ -176,16 +245,15 @@ const removeCollectionFromWorkspace = async (workspacePath, collectionPath) => {
|
||||
if (path.normalize(absoluteCollectionPath) === path.normalize(collectionPath)) {
|
||||
removedCollection = c;
|
||||
|
||||
// Delete files only for workspace collections (not remote, not external absolute paths)
|
||||
const hasRemote = c.remote;
|
||||
const isExternalPath = path.isAbsolute(collectionPathFromYml);
|
||||
|
||||
shouldDeleteFiles = !hasRemote && !isExternalPath;
|
||||
|
||||
return false; // Remove from array
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // Keep in array
|
||||
return true;
|
||||
});
|
||||
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
@@ -214,67 +282,63 @@ const getWorkspaceCollections = (workspacePath) => {
|
||||
|
||||
const getWorkspaceApiSpecs = (workspacePath) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
const apiSpecs = config.apiSpecs || [];
|
||||
const specs = config.specs || [];
|
||||
|
||||
// Resolve relative paths to absolute
|
||||
return apiSpecs.map((apiSpec) => {
|
||||
if (apiSpec.path && !path.isAbsolute(apiSpec.path)) {
|
||||
return specs.map((spec) => {
|
||||
if (spec.path && !path.isAbsolute(spec.path)) {
|
||||
return {
|
||||
...apiSpec,
|
||||
path: path.join(workspacePath, apiSpec.path)
|
||||
...spec,
|
||||
path: path.join(workspacePath, spec.path)
|
||||
};
|
||||
}
|
||||
return apiSpec;
|
||||
return spec;
|
||||
});
|
||||
};
|
||||
|
||||
const addApiSpecToWorkspace = async (workspacePath, apiSpec) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
|
||||
if (!config.apiSpecs) {
|
||||
config.apiSpecs = [];
|
||||
if (!config.specs) {
|
||||
config.specs = [];
|
||||
}
|
||||
|
||||
// Normalize API spec entry with relative path
|
||||
const normalizedApiSpec = {
|
||||
const normalizedSpec = {
|
||||
name: apiSpec.name,
|
||||
path: makeRelativePath(workspacePath, apiSpec.path)
|
||||
};
|
||||
|
||||
// Check if API spec already exists
|
||||
const existingIndex = config.apiSpecs.findIndex(
|
||||
(a) => a.name === normalizedApiSpec.name || a.path === normalizedApiSpec.path
|
||||
const existingIndex = config.specs.findIndex(
|
||||
(a) => a.name === normalizedSpec.name || a.path === normalizedSpec.path
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
config.apiSpecs[existingIndex] = normalizedApiSpec;
|
||||
config.specs[existingIndex] = normalizedSpec;
|
||||
} else {
|
||||
config.apiSpecs.push(normalizedApiSpec);
|
||||
config.specs.push(normalizedSpec);
|
||||
}
|
||||
|
||||
await writeWorkspaceConfig(workspacePath, config);
|
||||
return config.apiSpecs;
|
||||
return config.specs;
|
||||
};
|
||||
|
||||
const removeApiSpecFromWorkspace = async (workspacePath, apiSpecPath) => {
|
||||
const config = readWorkspaceConfig(workspacePath);
|
||||
|
||||
if (!config.apiSpecs) {
|
||||
if (!config.specs) {
|
||||
return { removedApiSpec: null, updatedConfig: config };
|
||||
}
|
||||
|
||||
let removedApiSpec = null;
|
||||
|
||||
config.apiSpecs = config.apiSpecs.filter((a) => {
|
||||
const apiSpecPathFromYml = a.path;
|
||||
if (!apiSpecPathFromYml) return true;
|
||||
config.specs = config.specs.filter((a) => {
|
||||
const specPathFromYml = a.path;
|
||||
if (!specPathFromYml) return true;
|
||||
|
||||
// Convert to absolute path for comparison
|
||||
const absoluteApiSpecPath = path.isAbsolute(apiSpecPathFromYml)
|
||||
? apiSpecPathFromYml
|
||||
: path.resolve(workspacePath, apiSpecPathFromYml);
|
||||
const absoluteSpecPath = path.isAbsolute(specPathFromYml)
|
||||
? specPathFromYml
|
||||
: path.resolve(workspacePath, specPathFromYml);
|
||||
|
||||
if (path.normalize(absoluteApiSpecPath) === path.normalize(apiSpecPath)) {
|
||||
if (path.normalize(absoluteSpecPath) === path.normalize(apiSpecPath)) {
|
||||
removedApiSpec = a;
|
||||
return false;
|
||||
}
|
||||
@@ -306,5 +370,6 @@ module.exports = {
|
||||
getWorkspaceCollections,
|
||||
getWorkspaceApiSpecs,
|
||||
addApiSpecToWorkspace,
|
||||
removeApiSpecFromWorkspace
|
||||
removeApiSpecFromWorkspace,
|
||||
generateYamlContent
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user