@pactflow/openapi-pact-comparator 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ import type { OpenAPIV2, OpenAPIV3 } from "openapi-types";
2
+ import type { Pact } from "#documents/pact";
3
+ import type { Result } from "#results/index";
4
+ export declare class Comparator {
5
+ #private;
6
+ constructor(oas: OpenAPIV2.Document | OpenAPIV3.Document);
7
+ compare(pact: Pact): AsyncGenerator<Result>;
8
+ }
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Interaction } from "#documents/pact";
4
+ import type { Result } from "#results/index";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareReqBody(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Interaction } from "#documents/pact";
4
+ import type { Result } from "#results/index";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareReqHeader(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Interaction } from "#documents/pact";
4
+ import type { Result } from "#results/index";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareReqPath(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Result } from "#results/index";
4
+ import type { Interaction } from "#documents/pact";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareReqQuery(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Interaction } from "#documents/pact";
4
+ import type { Result } from "#results/index";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareReqSecurity(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Interaction } from "#documents/pact";
4
+ import type { Result } from "#results/index";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareResBody(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type Ajv from "ajv/dist/2019";
2
+ import type Router from "find-my-way";
3
+ import type { Interaction } from "#documents/pact";
4
+ import type { Result } from "#results/index";
5
+ import type { Config } from "#utils/config";
6
+ export declare function compareResHeader(ajv: Ajv, route: Router.FindResult<Router.HTTPVersion.V1>, interaction: Interaction, index: number, _config: Config): Iterable<Result>;
@@ -0,0 +1,6 @@
1
+ import type { OpenAPIV2, OpenAPIV3 } from "openapi-types";
2
+ import Ajv, { Options } from "ajv/dist/2019.js";
3
+ import Router from "find-my-way";
4
+ import type { Config } from "#utils/config";
5
+ export declare function setupAjv(options: Options): Ajv;
6
+ export declare function setupRouter(oas: OpenAPIV2.Document | OpenAPIV3.Document, config: Config): Router.Instance<Router.HTTPVersion.V1>;
@@ -0,0 +1,7 @@
1
+ import type { SchemaObject } from "ajv";
2
+ export declare function findMatchingType(requestType: string, responseTypes: string[]): string | undefined;
3
+ export declare const getByContentType: (object: {} | undefined, contentType: string) => {
4
+ schema: SchemaObject;
5
+ };
6
+ export declare const standardHttpRequestHeaders: string[];
7
+ export declare const standardHttpResponseHeaders: string[];
@@ -0,0 +1 @@
1
+ export declare const cleanPathParameter: (s: string) => string;
@@ -0,0 +1,5 @@
1
+ import qs from "qs";
2
+ type QueryStyle = "form" | "spaceDelimited" | "pipeDelimited" | "deepObject";
3
+ export declare const parseQuery: (style: QueryStyle, explode: boolean) => (query: string) => qs.ParsedQs;
4
+ export declare const parseValue: (query?: string | null) => string | string[] | qs.ParsedQs | null | undefined;
5
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { OpenAPIV2, OpenAPIV3 } from "openapi-types";
2
+ export declare const parse: (oas: OpenAPIV2.Document | OpenAPIV3.Document) => Promise<void>;
3
+ export declare class ParserError extends Error {
4
+ constructor();
5
+ }
@@ -0,0 +1,54 @@
1
+ import { Static } from "@sinclair/typebox";
2
+ import { ErrorObject } from "ajv";
3
+ export declare const Interaction: import("@sinclair/typebox").TObject<{
4
+ type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
5
+ description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
6
+ providerState: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ request: import("@sinclair/typebox").TObject<{
8
+ body: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
9
+ headers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TNull, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>]>>;
10
+ method: import("@sinclair/typebox").TString;
11
+ path: import("@sinclair/typebox").TString;
12
+ query: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TNull, import("@sinclair/typebox").TString, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>]>>;
13
+ }>;
14
+ response: import("@sinclair/typebox").TObject<{
15
+ body: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
16
+ headers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TNull, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>]>>;
17
+ status: import("@sinclair/typebox").TNumber;
18
+ }>;
19
+ }>;
20
+ export type Interaction = Static<typeof Interaction>;
21
+ export declare const Pact: import("@sinclair/typebox").TObject<{
22
+ metadata: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
23
+ pactSpecification: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
24
+ version: import("@sinclair/typebox").TString;
25
+ }>>;
26
+ pactSpecificationVersion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
27
+ "pact-specification": import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
28
+ version: import("@sinclair/typebox").TString;
29
+ }>>;
30
+ }>>;
31
+ interactions: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
32
+ type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
33
+ description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
34
+ providerState: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
35
+ request: import("@sinclair/typebox").TObject<{
36
+ body: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
37
+ headers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TNull, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>]>>;
38
+ method: import("@sinclair/typebox").TString;
39
+ path: import("@sinclair/typebox").TString;
40
+ query: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TNull, import("@sinclair/typebox").TString, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>]>>;
41
+ }>;
42
+ response: import("@sinclair/typebox").TObject<{
43
+ body: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
44
+ headers: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TNull, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TString>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>]>>;
45
+ status: import("@sinclair/typebox").TNumber;
46
+ }>;
47
+ }>>;
48
+ }>;
49
+ export type Pact = Static<typeof Pact>;
50
+ export declare const parse: (pact: Pact) => Pact;
51
+ export declare class ParserError extends Error {
52
+ errors: ErrorObject[];
53
+ constructor(errors: ErrorObject[]);
54
+ }
@@ -0,0 +1 @@
1
+ export * from "./compare";
@@ -0,0 +1,29 @@
1
+ import type { ErrorObject } from "ajv";
2
+ import type { Interaction } from "../documents/pact";
3
+ type ErrorCode = "request.accept.incompatible" | "request.authorization.missing" | "request.body.incompatible" | "request.content-type.incompatible" | "request.header.incompatible" | "request.path-or-method.unknown" | "request.query.incompatible" | "response.body.incompatible" | "response.body.unknown" | "response.content-type.incompatible" | "response.header.incompatible" | "response.header.unknown" | "response.status.unknown";
4
+ type WarningCode = "pact-broker.no-pacts-found" | "request.accept.unknown" | "request.body.unknown" | "request.content-type.missing" | "request.content-type.unknown" | "request.header.unknown" | "request.query.unknown" | "response.content-type.unknown" | "response.header.undefined" | "response.status.default";
5
+ export interface Result {
6
+ code: ErrorCode | WarningCode;
7
+ message: string;
8
+ mockDetails?: {
9
+ interactionDescription?: string | null;
10
+ interactionState?: string | null;
11
+ location: string;
12
+ value: unknown;
13
+ };
14
+ specDetails?: {
15
+ location: string;
16
+ pathMethod?: string | null;
17
+ pathName?: string | null;
18
+ value: unknown;
19
+ };
20
+ type: "error" | "warning";
21
+ }
22
+ export declare const formatMessage: (error: ErrorObject) => string | undefined;
23
+ export declare const formatInstancePath: (error: ErrorObject) => string;
24
+ export declare const formatSchemaPath: (error: ErrorObject) => string;
25
+ export declare const baseMockDetails: (interaction: Interaction) => {
26
+ interactionDescription: string | undefined;
27
+ interactionState: string;
28
+ };
29
+ export {};
@@ -0,0 +1,3 @@
1
+ export { transformRequestSchema } from "./requestSchema";
2
+ export { transformResponseSchema } from "./responseSchema";
3
+ export { minimumSchema } from "./minimumSchema";
@@ -0,0 +1,3 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+ import { SchemaObject } from "ajv";
3
+ export declare const minimumSchema: (originalSchema: SchemaObject, oas: OpenAPIV3.Document) => SchemaObject;
@@ -0,0 +1,2 @@
1
+ import { SchemaObject } from "ajv";
2
+ export declare const transformRequestSchema: (schema: SchemaObject) => SchemaObject;
@@ -0,0 +1,2 @@
1
+ import { SchemaObject } from "ajv";
2
+ export declare const transformResponseSchema: (schema: SchemaObject, noTransformNonNullableResponseSchema: boolean) => SchemaObject;
@@ -0,0 +1,3 @@
1
+ export type ConfigKeys = "cast-objects-in-pact" | "disable-multipart-formdata" | "ignore-duplicate-slashes" | "ignore-trailing-slash" | "legacy-parser" | "no-authorization-schema" | "no-percent-encoding" | "no-transform-non-nullable-response-schema" | "no-validate-complex-parameters" | "no-validate-request-body-unless-application-json";
2
+ export type Config = Map<ConfigKeys, boolean>;
3
+ export declare const DEFAULT_CONFIG: Config;
@@ -0,0 +1,2 @@
1
+ import type { Interaction } from "../documents/pact";
2
+ export declare const isValidRequest: (interaction: Interaction) => boolean;
@@ -0,0 +1 @@
1
+ export declare const ARRAY_SEPARATOR = ",";
@@ -0,0 +1,3 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+ import type { SchemaObject } from "ajv";
3
+ export declare const isSimpleSchema: (s: SchemaObject | undefined, oas: OpenAPIV3.Document) => boolean;
@@ -0,0 +1,6 @@
1
+ import type { OpenAPIV3 } from "openapi-types";
2
+ import type { SchemaObject } from "ajv";
3
+ export declare const splitPath: (path: string) => string | string[];
4
+ export declare const dereferenceOas: (schema: SchemaObject, oas: OpenAPIV3.Document) => any;
5
+ export declare const traverse: (schema: SchemaObject, visitor: (schema: SchemaObject) => void) => void;
6
+ export declare const traverseWithDereferencing: (schema: SchemaObject, visitor: (schema: SchemaObject) => void) => void;
@@ -0,0 +1,2 @@
1
+ import Ajv, { AnySchema, ValidateFunction } from "ajv";
2
+ export declare const getValidateFunction: (ajv: Ajv, schemaId: string, create: () => AnySchema) => ValidateFunction;
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@pactflow/openapi-pact-comparator",
3
+ "version": "0.0.1",
4
+ "description": "An OpenAPI Specification and Pact Comparison library",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.mjs",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "require": "./dist/index.cjs",
13
+ "import": "./dist/index.mjs",
14
+ "types": "./dist/src/index.d.ts"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "rollup --config",
19
+ "changeset:add": "changeset add",
20
+ "changeset:publish": "changeset publish",
21
+ "changeset:version": "changeset version",
22
+ "lint": "eslint --max-warnings=0",
23
+ "postinstall": "patch-package",
24
+ "prepare": "npm run build",
25
+ "prettier": "prettier --check .",
26
+ "prettier:fix": "prettier --cache --list-different --write .",
27
+ "start": "node dist/cli.mjs",
28
+ "test": "vitest",
29
+ "test:coverage": "vitest --coverage",
30
+ "typecheck": "tsc --project tsconfig.json"
31
+ },
32
+ "keywords": [],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/pactflow/openapi-pact-comparator.git"
36
+ },
37
+ "author": {
38
+ "name": "Voon Siong Wong",
39
+ "email": "voon.wong@smartbear.com"
40
+ },
41
+ "license": "Apache-2.0",
42
+ "type": "module",
43
+ "devDependencies": {
44
+ "@apidevtools/swagger-parser": "10.1.1",
45
+ "@changesets/cli": "2.28.1",
46
+ "@eslint/js": "9.22.0",
47
+ "@pactflow/swagger-mock-validator": "14.5.0",
48
+ "@rollup/plugin-commonjs": "28.0.3",
49
+ "@rollup/plugin-json": "6.1.0",
50
+ "@rollup/plugin-node-resolve": "16.0.1",
51
+ "@rollup/plugin-typescript": "12.1.2",
52
+ "@sinclair/typebox": "0.34.30",
53
+ "@types/js-yaml": "4.0.9",
54
+ "@types/lodash-es": "4.17.12",
55
+ "@types/node": "22.13.10",
56
+ "@types/qs": "6.9.18",
57
+ "@vitest/coverage-v8": "3.0.9",
58
+ "ajv": "8.17.1",
59
+ "ajv-formats": "3.0.1",
60
+ "eslint": "9.22.0",
61
+ "eslint-config-prettier": "10.1.1",
62
+ "find-my-way": "9.2.0",
63
+ "js-yaml": "4.1.0",
64
+ "lodash-es": "4.17.21",
65
+ "parse-multipart-data": "1.5.0",
66
+ "patch-package": "8.0.0",
67
+ "prettier": "3.5.3",
68
+ "qs": "6.14.0",
69
+ "rollup": "4.36.0",
70
+ "tslib": "2.8.1",
71
+ "tsx": "4.19.3",
72
+ "typescript": "5.8.2",
73
+ "typescript-eslint": "8.26.1",
74
+ "vitest": "3.0.9"
75
+ },
76
+ "imports": {
77
+ "#compare/*": "./src/compare/*.ts",
78
+ "#documents/*": "./src/documents/*.ts",
79
+ "#results/*": "./src/results/*.ts",
80
+ "#transform/*": "./src/transform/*.ts",
81
+ "#utils/*": "./src/utils/*.ts"
82
+ }
83
+ }