mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 14:49:53 +00:00
260 lines
8.6 KiB
TypeScript
260 lines
8.6 KiB
TypeScript
import clone from 'clone';
|
|
import { Insomnia4Data } from 'insomnia-importers';
|
|
import YAML from 'yaml';
|
|
|
|
import { isApiSpec } from '../models/api-spec';
|
|
import { isCookieJar } from '../models/cookie-jar';
|
|
import { isEnvironment } from '../models/environment';
|
|
import { isGrpcRequest } from '../models/grpc-request';
|
|
import type { BaseModel } from '../models/index';
|
|
import * as models from '../models/index';
|
|
import { isProtoDirectory } from '../models/proto-directory';
|
|
import { isProtoFile } from '../models/proto-file';
|
|
import { isRequest } from '../models/request';
|
|
import { isRequestGroup } from '../models/request-group';
|
|
import { isUnitTest } from '../models/unit-test';
|
|
import { isUnitTestSuite } from '../models/unit-test-suite';
|
|
import { isWorkspace, Workspace } from '../models/workspace';
|
|
import { resetKeys } from '../sync/ignore-keys';
|
|
import { trackEvent } from './analytics';
|
|
import {
|
|
EXPORT_TYPE_API_SPEC,
|
|
EXPORT_TYPE_COOKIE_JAR,
|
|
EXPORT_TYPE_ENVIRONMENT,
|
|
EXPORT_TYPE_GRPC_REQUEST,
|
|
EXPORT_TYPE_PROTO_DIRECTORY,
|
|
EXPORT_TYPE_PROTO_FILE,
|
|
EXPORT_TYPE_REQUEST,
|
|
EXPORT_TYPE_REQUEST_GROUP,
|
|
EXPORT_TYPE_UNIT_TEST,
|
|
EXPORT_TYPE_UNIT_TEST_SUITE,
|
|
EXPORT_TYPE_WORKSPACE,
|
|
getAppVersion,
|
|
} from './constants';
|
|
import { database as db } from './database';
|
|
import * as har from './har';
|
|
|
|
const EXPORT_FORMAT = 4;
|
|
|
|
const getDocWithDescendants = (includePrivateDocs = false) => async (parentDoc: BaseModel | null) => {
|
|
const docs = await db.withDescendants(parentDoc);
|
|
return docs.filter(
|
|
// Don't include if private, except if we want to
|
|
doc => !doc?.isPrivate || includePrivateDocs,
|
|
);
|
|
};
|
|
|
|
export async function exportWorkspacesHAR(
|
|
workspaces: Workspace[],
|
|
includePrivateDocs = false,
|
|
) {
|
|
const promises = workspaces.map(getDocWithDescendants(includePrivateDocs));
|
|
const docs = (await Promise.all(promises)).flat();
|
|
const requests = docs.filter(isRequest);
|
|
return exportRequestsHAR(requests, includePrivateDocs);
|
|
}
|
|
|
|
export async function exportRequestsHAR(
|
|
requests: BaseModel[],
|
|
includePrivateDocs = false,
|
|
) {
|
|
const workspaces: BaseModel[] = [];
|
|
const mapRequestIdToWorkspace: Record<string, any> = {};
|
|
const workspaceLookup: Record<string, any> = {};
|
|
|
|
for (const request of requests) {
|
|
const ancestors: BaseModel[] = await db.withAncestors(request, [
|
|
models.workspace.type,
|
|
models.requestGroup.type,
|
|
]);
|
|
const workspace = ancestors.find(isWorkspace);
|
|
mapRequestIdToWorkspace[request._id] = workspace;
|
|
|
|
if (workspace == null || workspaceLookup.hasOwnProperty(workspace._id)) {
|
|
continue;
|
|
}
|
|
|
|
workspaceLookup[workspace._id] = true;
|
|
workspaces.push(workspace);
|
|
}
|
|
|
|
const mapWorkspaceIdToEnvironmentId: Record<string, any> = {};
|
|
|
|
for (const workspace of workspaces) {
|
|
const workspaceMeta = await models.workspaceMeta.getByParentId(workspace._id);
|
|
let environmentId = workspaceMeta ? workspaceMeta.activeEnvironmentId : null;
|
|
const environment = await models.environment.getById(environmentId || 'n/a');
|
|
|
|
if (!environment || (environment.isPrivate && !includePrivateDocs)) {
|
|
environmentId = 'n/a';
|
|
}
|
|
|
|
mapWorkspaceIdToEnvironmentId[workspace._id] = environmentId;
|
|
}
|
|
|
|
requests = requests.sort((a: Record<string, any>, b: Record<string, any>) =>
|
|
a.metaSortKey < b.metaSortKey ? -1 : 1,
|
|
);
|
|
const harRequests: har.ExportRequest[] = [];
|
|
|
|
for (const request of requests) {
|
|
const workspace = mapRequestIdToWorkspace[request._id];
|
|
|
|
if (workspace == null) {
|
|
// Workspace not found for request, so don't export it.
|
|
continue;
|
|
}
|
|
|
|
const environmentId = mapWorkspaceIdToEnvironmentId[workspace._id];
|
|
harRequests.push({
|
|
requestId: request._id,
|
|
environmentId: environmentId,
|
|
});
|
|
}
|
|
|
|
const data = await har.exportHar(harRequests);
|
|
trackEvent('Data', 'Export', 'HAR');
|
|
return JSON.stringify(data, null, '\t');
|
|
}
|
|
|
|
export async function exportWorkspacesData(
|
|
workspaces: Workspace[],
|
|
includePrivateDocs: boolean,
|
|
format: 'json' | 'yaml',
|
|
) {
|
|
const promises = workspaces.map(getDocWithDescendants(includePrivateDocs));
|
|
const docs = (await Promise.all(promises)).flat();
|
|
const requests = docs.filter(doc => isRequest(doc) || isGrpcRequest(doc));
|
|
return exportRequestsData(requests, includePrivateDocs, format);
|
|
}
|
|
|
|
export async function exportRequestsData(
|
|
requests: BaseModel[],
|
|
includePrivateDocs: boolean,
|
|
format: 'json' | 'yaml',
|
|
) {
|
|
const data: Insomnia4Data = {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
_type: 'export',
|
|
__export_format: EXPORT_FORMAT,
|
|
__export_date: new Date(),
|
|
__export_source: `insomnia.desktop.app:v${getAppVersion()}`,
|
|
resources: [],
|
|
};
|
|
const docs: BaseModel[] = [];
|
|
const workspaces: Workspace[] = [];
|
|
const mapTypeAndIdToDoc: Record<string, BaseModel> = {};
|
|
|
|
for (const request of requests) {
|
|
const ancestors = clone<BaseModel[]>(await db.withAncestors(request));
|
|
|
|
for (const ancestor of ancestors) {
|
|
const key = ancestor.type + '___' + ancestor._id;
|
|
|
|
if (mapTypeAndIdToDoc.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
|
|
mapTypeAndIdToDoc[key] = ancestor;
|
|
docs.push(ancestor);
|
|
|
|
if (isWorkspace(ancestor)) {
|
|
workspaces.push(ancestor);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const workspace of workspaces) {
|
|
const descendants = (await db.withDescendants(workspace)).filter(d => {
|
|
// Only interested in these additional model types.
|
|
return (
|
|
isCookieJar(d) ||
|
|
isEnvironment(d) ||
|
|
isApiSpec(d) ||
|
|
isUnitTestSuite(d) ||
|
|
isUnitTest(d) ||
|
|
isProtoFile(d) ||
|
|
isProtoDirectory(d)
|
|
);
|
|
});
|
|
docs.push(...descendants);
|
|
}
|
|
|
|
data.resources = docs
|
|
.filter(d => {
|
|
// Only export these model types.
|
|
if (
|
|
!(
|
|
isUnitTestSuite(d) ||
|
|
isUnitTest(d) ||
|
|
isRequest(d) ||
|
|
isGrpcRequest(d) ||
|
|
isRequestGroup(d) ||
|
|
isProtoFile(d) ||
|
|
isProtoDirectory(d) ||
|
|
isWorkspace(d) ||
|
|
isCookieJar(d) ||
|
|
isEnvironment(d) ||
|
|
isApiSpec(d)
|
|
)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// BaseModel doesn't have isPrivate, so cast it first.
|
|
return !d.isPrivate || includePrivateDocs;
|
|
})
|
|
.map(d => {
|
|
if (isWorkspace(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_WORKSPACE;
|
|
// reset the parentId of a workspace
|
|
resetKeys(d);
|
|
} else if (isCookieJar(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_COOKIE_JAR;
|
|
} else if (isEnvironment(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_ENVIRONMENT;
|
|
} else if (isUnitTestSuite(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_UNIT_TEST_SUITE;
|
|
} else if (isUnitTest(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_UNIT_TEST;
|
|
} else if (isRequestGroup(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_REQUEST_GROUP;
|
|
} else if (isRequest(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_REQUEST;
|
|
} else if (isGrpcRequest(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_GRPC_REQUEST;
|
|
} else if (isProtoFile(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_PROTO_FILE;
|
|
} else if (isProtoDirectory(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_PROTO_DIRECTORY;
|
|
} else if (isApiSpec(d)) {
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
d._type = EXPORT_TYPE_API_SPEC;
|
|
}
|
|
|
|
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
|
|
// Delete the things we don't want to export
|
|
delete d.type;
|
|
return d;
|
|
});
|
|
trackEvent('Data', 'Export', `Insomnia ${format}`);
|
|
|
|
if (format.toLowerCase() === 'yaml') {
|
|
return YAML.stringify(data);
|
|
} else if (format.toLowerCase() === 'json') {
|
|
return JSON.stringify(data);
|
|
} else {
|
|
throw new Error(`Invalid export format ${format}. Must be "json" or "yaml"`);
|
|
}
|
|
}
|