UNPKG

@firfi/quint-connect

Version:

Model-based testing framework connecting Quint specifications to TypeScript implementations

53 lines 2.79 kB
import { Effect, Predicate, Schema } from "effect"; import { QuintError } from "./errors.js"; const JSON_INTEGER_LITERAL = /^-?(?:0|[1-9]\d*)$/; const EvaluatorTrace = Schema.Struct({ "#meta": Schema.optional(Schema.Unknown), vars: Schema.Array(Schema.String), states: Schema.Array(Schema.Record({ key: Schema.String, value: Schema.Unknown })) }); const EvaluatorBestTrace = Schema.Struct({ states: EvaluatorTrace }); const EvaluatorSuccessOutput = Schema.Struct({ status: Schema.Literal("ok"), bestTraces: Schema.Array(EvaluatorBestTrace) }); const EvaluatorOutput = Schema.Record({ key: Schema.String, value: Schema.Unknown }); const EvaluatorFailureOutput = Schema.Struct({ status: Schema.Literal("error"), errors: Schema.Array(Schema.Unknown) }); const formatEvaluatorError = (error) => Predicate.isRecord(error) && typeof error["message"] === "string" ? error["message"] : String(error); const parseJsonPreservingIntegers = (json) => JSON.parse(json, (_key, value, context) => { if (typeof value !== "number") { return value; } if (typeof context?.source !== "string") { throw new Error("Lossless evaluator JSON decoding requires Node.js 22 or newer"); } return JSON_INTEGER_LITERAL.test(context.source) ? BigInt(context.source) : value; }); const invalidEvaluatorOutput = (error) => new QuintError({ message: `Invalid evaluator output: ${error}` }); export const normalizeEvaluatorOutput = (stdout) => Effect.gen(function* () { const jsonLine = stdout.split("\n").filter((line) => line.trimStart().startsWith("{")).pop(); if (jsonLine === undefined) { return yield* new QuintError({ message: "No JSON output from Rust evaluator" }); } const parsedJson = yield* Effect.try({ try: () => parseJsonPreservingIntegers(jsonLine), catch: (error) => new QuintError({ message: `Failed to parse evaluator output: ${error}` }) }); const envelope = yield* Schema.decodeUnknown(EvaluatorOutput)(parsedJson).pipe(Effect.mapError(invalidEvaluatorOutput)); if (envelope["status"] === "error") { const failure = yield* Schema.decodeUnknown(EvaluatorFailureOutput)(parsedJson).pipe(Effect.mapError(invalidEvaluatorOutput)); return yield* new QuintError({ message: `Quint simulation error:\n${failure.errors.map(formatEvaluatorError).join("\n")}` }); } const success = yield* Schema.decodeUnknown(EvaluatorSuccessOutput)(parsedJson).pipe(Effect.mapError(invalidEvaluatorOutput)); return success.bestTraces.map(({ states }) => ({ vars: states.vars, states: states.states, ...(!Object.hasOwn(states, "#meta") ? {} : { "#meta": states["#meta"] }) })); }); //# sourceMappingURL=compiled-evaluator-output.js.map