Compare commits
1 Commits
2024.7.0-l
...
feat/cli-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dc9030559 |
@@ -3,7 +3,7 @@ import { ExecException } from "child_process";
|
||||
import { HoppErrorCode } from "../../types/errors";
|
||||
import { runCLI, getErrorCode, getTestJsonFilePath } from "../utils";
|
||||
|
||||
describe("Test `hopp test <file>` command:", () => {
|
||||
describe("Test `hopp test <file_path_or_id>` command:", () => {
|
||||
describe("Argument parsing", () => {
|
||||
test("Errors with the code `INVALID_ARGUMENT` for not supplying enough arguments", async () => {
|
||||
const args = "test";
|
||||
@@ -131,7 +131,7 @@ describe("Test `hopp test <file>` command:", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test `hopp test <file> --env <file>` command:", () => {
|
||||
describe("Test `hopp test <file_path_or_id> --env <file_path_or_id>` command:", () => {
|
||||
describe("Supplied environment export file validations", () => {
|
||||
const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
||||
|
||||
@@ -310,7 +310,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test `hopp test <file> --delay <delay_in_ms>` command:", () => {
|
||||
describe("Test `hopp test <file_path_or_id> --delay <delay_in_ms>` command:", () => {
|
||||
const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
||||
|
||||
test("Errors with the code `INVALID_ARGUMENT` on not supplying a delay value", async () => {
|
||||
@@ -343,3 +343,116 @@ describe("Test `hopp test <file> --delay <delay_in_ms>` command:", () => {
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip("Test `hopp test <file_path_or_id> --env <file_path_or_id> --token <access_token> --server <server_url>` command:", () => {
|
||||
const {
|
||||
REQ_BODY_ENV_VARS_COLL_ID,
|
||||
COLLECTION_LEVEL_HEADERS_AUTH_COLL_ID,
|
||||
REQ_BODY_ENV_VARS_ENVS_ID,
|
||||
PERSONAL_ACCESS_TOKEN,
|
||||
} = process.env;
|
||||
|
||||
if (
|
||||
!REQ_BODY_ENV_VARS_COLL_ID ||
|
||||
!COLLECTION_LEVEL_HEADERS_AUTH_COLL_ID ||
|
||||
!REQ_BODY_ENV_VARS_ENVS_ID ||
|
||||
!PERSONAL_ACCESS_TOKEN
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SERVER_URL = "https://stage-shc.hoppscotch.io/backend";
|
||||
|
||||
describe("Validations", () => {
|
||||
test("Errors with the code `INVALID_ARGUMENT` on not supplying a value for the `--token` flag", async () => {
|
||||
const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --token`;
|
||||
const { stderr } = await runCLI(args);
|
||||
|
||||
const out = getErrorCode(stderr);
|
||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||
});
|
||||
|
||||
test("Errors with the code `INVALID_ARGUMENT` on not supplying a value for the `--server` flag", async () => {
|
||||
const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --server`;
|
||||
const { stderr } = await runCLI(args);
|
||||
|
||||
const out = getErrorCode(stderr);
|
||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||
});
|
||||
|
||||
test("Errors with the code `TOKEN_INVALID` if the supplied access token is invalid", async () => {
|
||||
const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --token invalid-token --server ${SERVER_URL}`;
|
||||
const { stderr } = await runCLI(args);
|
||||
|
||||
const out = getErrorCode(stderr);
|
||||
expect(out).toBe<HoppErrorCode>("TOKEN_INVALID");
|
||||
});
|
||||
|
||||
test("Errors with the code `TOKEN_INVALID` if the supplied collection ID is invalid", async () => {
|
||||
const args = `test invalid-id --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`;
|
||||
const { stderr } = await runCLI(args);
|
||||
|
||||
const out = getErrorCode(stderr);
|
||||
expect(out).toBe<HoppErrorCode>("INVALID_ID");
|
||||
});
|
||||
|
||||
test("Errors with the code `TOKEN_INVALID` if the supplied environment ID is invalid", async () => {
|
||||
const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env invalid-id --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`;
|
||||
const { stderr } = await runCLI(args);
|
||||
|
||||
const out = getErrorCode(stderr);
|
||||
expect(out).toBe<HoppErrorCode>("INVALID_ID");
|
||||
});
|
||||
});
|
||||
|
||||
test("Successfully retrieves a collection with the ID", async () => {
|
||||
const args = `test ${COLLECTION_LEVEL_HEADERS_AUTH_COLL_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`;
|
||||
|
||||
const { error } = await runCLI(args);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test("Successfully retrieves collections and environments from a workspace using their respective IDs", async () => {
|
||||
const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${REQ_BODY_ENV_VARS_ENVS_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`;
|
||||
|
||||
const { error } = await runCLI(args);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test("Supports specifying collection file path along with environment ID", async () => {
|
||||
const TESTS_PATH = getTestJsonFilePath(
|
||||
"req-body-env-vars-coll.json",
|
||||
"collection"
|
||||
);
|
||||
const args = `test ${TESTS_PATH} --env ${REQ_BODY_ENV_VARS_ENVS_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`;
|
||||
|
||||
const { error } = await runCLI(args);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test("Supports specifying environment file path along with collection ID", async () => {
|
||||
const ENV_PATH = getTestJsonFilePath(
|
||||
"req-body-env-vars-envs.json",
|
||||
"environment"
|
||||
);
|
||||
const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${ENV_PATH} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`;
|
||||
|
||||
const { error } = await runCLI(args);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test("Supports specifying both collection and environment file paths", async () => {
|
||||
const TESTS_PATH = getTestJsonFilePath(
|
||||
"req-body-env-vars-coll.json",
|
||||
"collection"
|
||||
);
|
||||
const ENV_PATH = getTestJsonFilePath(
|
||||
"req-body-env-vars-envs.json",
|
||||
"environment"
|
||||
);
|
||||
const args = `test ${TESTS_PATH} --env ${ENV_PATH} --token ${PERSONAL_ACCESS_TOKEN}`;
|
||||
|
||||
const { error } = await runCLI(args);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,30 +1,38 @@
|
||||
import { handleError } from "../handlers/error";
|
||||
import { parseDelayOption } from "../options/test/delay";
|
||||
import { parseEnvsData } from "../options/test/env";
|
||||
import { TestCmdOptions } from "../types/commands";
|
||||
import { HoppEnvs } from "../types/request";
|
||||
import { isHoppCLIError } from "../utils/checks";
|
||||
import {
|
||||
collectionsRunner,
|
||||
collectionsRunnerExit,
|
||||
collectionsRunnerResult,
|
||||
} from "../utils/collections";
|
||||
import { handleError } from "../handlers/error";
|
||||
import { parseCollectionData } from "../utils/mutators";
|
||||
import { parseEnvsData } from "../options/test/env";
|
||||
import { TestCmdOptions } from "../types/commands";
|
||||
import { parseDelayOption } from "../options/test/delay";
|
||||
import { HoppEnvs } from "../types/request";
|
||||
import { isHoppCLIError } from "../utils/checks";
|
||||
|
||||
export const test = (path: string, options: TestCmdOptions) => async () => {
|
||||
export const test = (pathOrId: string, options: TestCmdOptions) => async () => {
|
||||
try {
|
||||
const delay = options.delay ? parseDelayOption(options.delay) : 0
|
||||
const envs = options.env ? await parseEnvsData(options.env) : <HoppEnvs>{ global: [], selected: [] }
|
||||
const collections = await parseCollectionData(path)
|
||||
const delay = options.delay ? parseDelayOption(options.delay) : 0;
|
||||
|
||||
const report = await collectionsRunner({collections, envs, delay})
|
||||
const hasSucceeded = collectionsRunnerResult(report)
|
||||
collectionsRunnerExit(hasSucceeded)
|
||||
} catch(e) {
|
||||
if(isHoppCLIError(e)) {
|
||||
handleError(e)
|
||||
const envs = options.env
|
||||
? await parseEnvsData(options.env, options.token, options.server)
|
||||
: <HoppEnvs>{ global: [], selected: [] };
|
||||
|
||||
const collections = await parseCollectionData(
|
||||
pathOrId,
|
||||
options.token,
|
||||
options.server
|
||||
);
|
||||
|
||||
const report = await collectionsRunner({ collections, envs, delay });
|
||||
const hasSucceeded = collectionsRunnerResult(report);
|
||||
|
||||
collectionsRunnerExit(hasSucceeded);
|
||||
} catch (e) {
|
||||
if (isHoppCLIError(e)) {
|
||||
handleError(e);
|
||||
process.exit(1);
|
||||
}
|
||||
else throw e
|
||||
} else throw e;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -82,6 +82,15 @@ export const handleError = <T extends HoppErrorCode>(error: HoppError<T>) => {
|
||||
case "TESTS_FAILING":
|
||||
ERROR_MSG = error.data;
|
||||
break;
|
||||
case "TOKEN_EXPIRED":
|
||||
ERROR_MSG = `Token is expired: ${error.data}`;
|
||||
break;
|
||||
case "TOKEN_INVALID":
|
||||
ERROR_MSG = `Token is invalid/removed: ${error.data}`;
|
||||
break;
|
||||
case "INVALID_ID":
|
||||
ERROR_MSG = `The collection/environment is not valid/not accessible to the user: ${error.data}`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!S.isEmpty(ERROR_MSG)) {
|
||||
|
||||
@@ -49,14 +49,22 @@ program.exitOverride().configureOutput({
|
||||
program
|
||||
.command("test")
|
||||
.argument(
|
||||
"<file_path>",
|
||||
"path to a hoppscotch collection.json file for CI testing"
|
||||
"<file_path_or_id>",
|
||||
"path to a hoppscotch collection.json file or collection ID from a workspace for CI testing"
|
||||
)
|
||||
.option(
|
||||
"-e, --env <file_path_or_id>",
|
||||
"path to an environment variables json file or environment ID from a workspace"
|
||||
)
|
||||
.option("-e, --env <file_path>", "path to an environment variables json file")
|
||||
.option(
|
||||
"-d, --delay <delay_in_ms>",
|
||||
"delay in milliseconds(ms) between consecutive requests within a collection"
|
||||
)
|
||||
.option(
|
||||
"--token <access_token>",
|
||||
"personal access token to access collections/environments from a workspace"
|
||||
)
|
||||
.option("--server <server_url>", "server URL for SH instance")
|
||||
.allowExcessArguments(false)
|
||||
.allowUnknownOption(false)
|
||||
.description("running hoppscotch collection.json file")
|
||||
@@ -66,7 +74,7 @@ program
|
||||
"https://docs.hoppscotch.io/documentation/clients/cli#commands"
|
||||
)}`
|
||||
)
|
||||
.action(async (path, options) => await test(path, options)());
|
||||
.action(async (pathOrId, options) => await test(pathOrId, options)());
|
||||
|
||||
export const cli = async (args: string[]) => {
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Environment } from "@hoppscotch/data";
|
||||
import { Environment, EnvironmentSchemaVersion } from "@hoppscotch/data";
|
||||
import axios, { AxiosError } from "axios";
|
||||
import fs from "fs/promises";
|
||||
import { entityReference } from "verzod";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -10,13 +12,94 @@ import {
|
||||
} from "../../types/request";
|
||||
import { readJsonFile } from "../../utils/mutators";
|
||||
|
||||
interface WorkspaceEnvironment {
|
||||
id: string;
|
||||
teamID: string;
|
||||
name: string;
|
||||
variables: HoppEnvPair[];
|
||||
}
|
||||
|
||||
// Helper functions to transform workspace environment data to the `HoppEnvironment` format
|
||||
const transformWorkspaceEnvironment = (
|
||||
workspaceEnvironment: WorkspaceEnvironment
|
||||
): Environment => {
|
||||
const { teamID, variables, ...rest } = workspaceEnvironment;
|
||||
|
||||
// Add `secret` field if the data conforms to an older schema
|
||||
const transformedEnvVars = variables.map((variable) => {
|
||||
if (!("secret" in variable)) {
|
||||
return {
|
||||
...(variable as HoppEnvPair),
|
||||
secret: false,
|
||||
} as HoppEnvPair;
|
||||
}
|
||||
|
||||
return variable;
|
||||
});
|
||||
|
||||
return {
|
||||
v: EnvironmentSchemaVersion,
|
||||
variables: transformedEnvVars,
|
||||
...rest,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses env json file for given path and validates the parsed env json object
|
||||
* @param path Path of env.json file to be parsed
|
||||
* @param pathOrId Path of env.json file to be parsed
|
||||
* @param [accessToken] Personal access token to fetch workspace environments
|
||||
* @param [serverUrl] server URL for SH instance
|
||||
* @returns For successful parsing we get HoppEnvs object
|
||||
*/
|
||||
export async function parseEnvsData(path: string) {
|
||||
const contents = await readJsonFile(path);
|
||||
export async function parseEnvsData(
|
||||
pathOrId: string,
|
||||
accessToken?: string,
|
||||
serverUrl?: string
|
||||
) {
|
||||
let contents = null;
|
||||
let fileExistsInPath = null;
|
||||
|
||||
try {
|
||||
await fs.access(pathOrId);
|
||||
fileExistsInPath = true;
|
||||
} catch (e) {
|
||||
fileExistsInPath = false;
|
||||
}
|
||||
|
||||
if (accessToken && !fileExistsInPath) {
|
||||
try {
|
||||
const hostname = serverUrl || "https://api.hoppscotch.io";
|
||||
const url = `${hostname.endsWith("/") ? hostname.slice(0, -1) : hostname}/v1/access-tokens/environment/${pathOrId}`;
|
||||
|
||||
const { data }: { data: WorkspaceEnvironment } = await axios.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
contents = transformWorkspaceEnvironment(data);
|
||||
} catch (err) {
|
||||
const errReason = (
|
||||
err as AxiosError<{
|
||||
reason?: any;
|
||||
message: string;
|
||||
error: string;
|
||||
statusCode: number;
|
||||
}>
|
||||
).response?.data?.reason;
|
||||
|
||||
if (errReason) {
|
||||
throw error({
|
||||
code: errReason,
|
||||
data: pathOrId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contents === null) {
|
||||
contents = await readJsonFile(pathOrId);
|
||||
}
|
||||
const envPairs: Array<HoppEnvPair | Record<string, string>> = [];
|
||||
|
||||
// The legacy key-value pair format that is still supported
|
||||
@@ -33,7 +116,7 @@ export async function parseEnvsData(path: string) {
|
||||
// CLI doesnt support bulk environments export
|
||||
// Hence we check for this case and throw an error if it matches the format
|
||||
if (HoppBulkEnvExportObjectResult.success) {
|
||||
throw error({ code: "BULK_ENV_FILE", path, data: error });
|
||||
throw error({ code: "BULK_ENV_FILE", path: pathOrId, data: error });
|
||||
}
|
||||
|
||||
// Checks if the environment file is of the correct format
|
||||
@@ -42,7 +125,7 @@ export async function parseEnvsData(path: string) {
|
||||
!HoppEnvKeyPairResult.success &&
|
||||
HoppEnvExportObjectResult.type === "err"
|
||||
) {
|
||||
throw error({ code: "MALFORMED_ENV_FILE", path, data: error });
|
||||
throw error({ code: "MALFORMED_ENV_FILE", path: pathOrId, data: error });
|
||||
}
|
||||
|
||||
if (HoppEnvKeyPairResult.success) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export type TestCmdOptions = {
|
||||
env: string | undefined;
|
||||
delay: string | undefined;
|
||||
token: string | undefined;
|
||||
server: string | undefined;
|
||||
};
|
||||
|
||||
export type HOPP_ENV_FILE_EXT = "json";
|
||||
|
||||
@@ -26,6 +26,9 @@ type HoppErrors = {
|
||||
MALFORMED_ENV_FILE: HoppErrorPath & HoppErrorData;
|
||||
BULK_ENV_FILE: HoppErrorPath & HoppErrorData;
|
||||
INVALID_FILE_TYPE: HoppErrorData;
|
||||
TOKEN_EXPIRED: HoppErrorData;
|
||||
TOKEN_INVALID: HoppErrorData;
|
||||
INVALID_ID: HoppErrorData;
|
||||
};
|
||||
|
||||
export type HoppErrorCode = keyof HoppErrors;
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
||||
import {
|
||||
CollectionSchemaVersion,
|
||||
HoppCollection,
|
||||
HoppRESTRequest,
|
||||
} from "@hoppscotch/data";
|
||||
import fs from "fs/promises";
|
||||
import { entityReference } from "verzod";
|
||||
import { z } from "zod";
|
||||
|
||||
import axios, { AxiosError } from "axios";
|
||||
import { error } from "../types/errors";
|
||||
import { FormDataEntry } from "../types/request";
|
||||
import { isHoppErrnoException } from "./checks";
|
||||
|
||||
interface WorkspaceCollection {
|
||||
id: string;
|
||||
data: string | null;
|
||||
title: string;
|
||||
parentID: string | null;
|
||||
folders: WorkspaceCollection[];
|
||||
requests: WorkspaceRequest[];
|
||||
}
|
||||
|
||||
interface WorkspaceRequest {
|
||||
id: string;
|
||||
collectionID: string;
|
||||
teamID: string;
|
||||
title: string;
|
||||
request: string;
|
||||
}
|
||||
|
||||
const getValidRequests = (
|
||||
collections: HoppCollection[],
|
||||
collectionFilePath: string
|
||||
@@ -42,6 +64,50 @@ const getValidRequests = (
|
||||
});
|
||||
};
|
||||
|
||||
// Helper functions to transform workspace collection data to the `HoppCollection` format
|
||||
const transformWorkspaceRequests = (requests: WorkspaceRequest[]) =>
|
||||
requests.map(({ request }) => JSON.parse(request));
|
||||
|
||||
const transformChildCollections = (
|
||||
childCollections: WorkspaceCollection[]
|
||||
): HoppCollection[] => {
|
||||
return childCollections.map(({ id, title, data, folders, requests }) => {
|
||||
const parsedData = data ? JSON.parse(data) : {};
|
||||
const { auth = { authType: "inherit", authActive: false }, headers = [] } =
|
||||
parsedData;
|
||||
|
||||
return {
|
||||
v: CollectionSchemaVersion,
|
||||
id,
|
||||
name: title,
|
||||
folders: transformChildCollections(folders),
|
||||
requests: transformWorkspaceRequests(requests),
|
||||
auth,
|
||||
headers,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const transformWorkspaceCollection = (
|
||||
collection: WorkspaceCollection
|
||||
): HoppCollection => {
|
||||
const { id, title, data, requests, folders } = collection;
|
||||
|
||||
const parsedData = data ? JSON.parse(data) : {};
|
||||
const { auth = { authType: "inherit", authActive: false }, headers = [] } =
|
||||
parsedData;
|
||||
|
||||
return {
|
||||
v: CollectionSchemaVersion,
|
||||
id,
|
||||
name: title,
|
||||
folders: transformChildCollections(folders),
|
||||
requests: transformWorkspaceRequests(requests),
|
||||
auth,
|
||||
headers,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses array of FormDataEntry to FormData.
|
||||
* @param values Array of FormDataEntry.
|
||||
@@ -92,16 +158,64 @@ export async function readJsonFile(path: string): Promise<unknown> {
|
||||
|
||||
/**
|
||||
* Parses collection json file for given path:context.path, and validates
|
||||
* the parsed collectiona array.
|
||||
* @param path Collection json file path.
|
||||
* @returns For successful parsing we get array of HoppCollection,
|
||||
* the parsed collectiona array
|
||||
* @param pathOrId Collection json file path
|
||||
* @param [accessToken] Personal access token to fetch workspace environments
|
||||
* @param [serverUrl] server URL for SH instance
|
||||
* @returns For successful parsing we get array of HoppCollection
|
||||
*/
|
||||
export async function parseCollectionData(
|
||||
path: string
|
||||
pathOrId: string,
|
||||
accessToken?: string,
|
||||
serverUrl?: string
|
||||
): Promise<HoppCollection[]> {
|
||||
let contents = await readJsonFile(path);
|
||||
let contents = null;
|
||||
let fileExistsInPath = null;
|
||||
|
||||
const maybeArrayOfCollections: unknown[] = Array.isArray(contents)
|
||||
try {
|
||||
await fs.access(pathOrId);
|
||||
fileExistsInPath = true;
|
||||
} catch (e) {
|
||||
fileExistsInPath = false;
|
||||
}
|
||||
|
||||
if (accessToken && !fileExistsInPath) {
|
||||
try {
|
||||
const hostname = serverUrl || "https://api.hoppscotch.io";
|
||||
const url = `${hostname.endsWith("/") ? hostname.slice(0, -1) : hostname}/v1/access-tokens/collection/${pathOrId}`;
|
||||
|
||||
const { data }: { data: WorkspaceCollection } = await axios.get(url, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
contents = transformWorkspaceCollection(data);
|
||||
} catch (err) {
|
||||
const errReason = (
|
||||
err as AxiosError<{
|
||||
reason?: any;
|
||||
message: string;
|
||||
error: string;
|
||||
statusCode: number;
|
||||
}>
|
||||
).response?.data?.reason;
|
||||
|
||||
if (errReason) {
|
||||
throw error({
|
||||
code: errReason,
|
||||
data: pathOrId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to reading from file if contents are not available
|
||||
if (contents === null) {
|
||||
contents = await readJsonFile(pathOrId);
|
||||
}
|
||||
|
||||
const maybeArrayOfCollections: HoppCollection[] = Array.isArray(contents)
|
||||
? contents
|
||||
: [contents];
|
||||
|
||||
@@ -110,12 +224,14 @@ export async function parseCollectionData(
|
||||
.safeParse(maybeArrayOfCollections);
|
||||
|
||||
if (!collectionSchemaParsedResult.success) {
|
||||
console.error(`Error is `, collectionSchemaParsedResult.error);
|
||||
|
||||
throw error({
|
||||
code: "MALFORMED_COLLECTION",
|
||||
path,
|
||||
path: pathOrId,
|
||||
data: "Please check the collection data.",
|
||||
});
|
||||
}
|
||||
|
||||
return getValidRequests(collectionSchemaParsedResult.data, path);
|
||||
return getValidRequests(collectionSchemaParsedResult.data, pathOrId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user