MCPcopy Create free account
hub / github.com/TestSprite/testsprite-cli / assertPlanShape

Function assertPlanShape

src/commands/test.ts:2033–2080  ·  view source on GitHub ↗

* Type-narrow + validate a parsed plan input. Pulled out so the same * checks run on `--plan-from` (single) and each JSONL line in * `create-batch --plans`. Throws `VALIDATION_ERROR` with a typed * `details.field` pointer so callers can fix specific issues without * re-reading the whole file.

(parsed: unknown, context: { specIndex?: number } = {})

Source from the content-addressed store, hash-verified

2031 * re-reading the whole file.
2032 */
2033function assertPlanShape(parsed: unknown, context: { specIndex?: number } = {}): CliPlanInput {
2034 const prefix = context.specIndex !== undefined ? `specs[${context.specIndex}].` : '';
2035
2036 // Every field below is a JSON body path inside the plan file (or
2037 // JSONL spec), not a CLI flag — pass `'field'` so the error message
2038 // says `Field \`projectId\` is invalid: ...` instead of inventing a
2039 // `--projectId` flag the user can't pass.
2040 if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
2041 throw localValidationError(`${prefix}plan`, 'must be a JSON object', undefined, 'field');
2042 }
2043 const obj = parsed as Record<string, unknown>;
2044
2045 requireString(`${prefix}projectId`, obj.projectId);
2046 requireEnum(`${prefix}type`, obj.type, ['frontend', 'backend'] as const);
2047 requireString(`${prefix}name`, obj.name);
2048 if (obj.description !== undefined && typeof obj.description !== 'string') {
2049 throw localValidationError(
2050 `${prefix}description`,
2051 'must be a string when present',
2052 undefined,
2053 'field',
2054 );
2055 }
2056 if (obj.priority !== undefined) {
2057 requireEnum(`${prefix}priority`, obj.priority, CLI_CREATE_PRIORITIES);
2058 }
2059 requireArrayLength(`${prefix}planSteps`, obj.planSteps, {
2060 min: 1,
2061 max: MAX_PLAN_STEPS,
2062 itemNoun: 'step',
2063 });
2064 for (let i = 0; i < (obj.planSteps as unknown[]).length; i += 1) {
2065 const step = (obj.planSteps as unknown[])[i];
2066 if (typeof step !== 'object' || step === null || Array.isArray(step)) {
2067 throw localValidationError(
2068 `${prefix}planSteps[${i}]`,
2069 'must be an object',
2070 undefined,
2071 'field',
2072 );
2073 }
2074 const s = step as Record<string, unknown>;
2075 requireEnum(`${prefix}planSteps[${i}].type`, s.type, PLAN_STEP_TYPES);
2076 requireString(`${prefix}planSteps[${i}].description`, s.description);
2077 }
2078
2079 return obj as unknown as CliPlanInput;
2080}
2081
2082interface CreateBatchOptions extends CommonOptions {
2083 /** Path to the JSONL file containing one `CliPlanInput` per line. */

Callers 3

readPlanFromGuardedFunction · 0.85
readPlansJsonlGuardedFunction · 0.85
readPlansFromDirGuardedFunction · 0.85

Calls 4

requireStringFunction · 0.85
requireEnumFunction · 0.85
requireArrayLengthFunction · 0.85
localValidationErrorFunction · 0.70

Tested by

no test coverage detected