assert-json-body 1.0.2
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.
- package/README.md +352 -0
- package/dist/assertion/diff-recordings-vs-spec.d.ts +3 -0
- package/dist/assertion/diff-recordings-vs-spec.d.ts.map +1 -0
- package/dist/assertion/diff-recordings-vs-spec.js +176 -0
- package/dist/assertion/diff-recordings-vs-spec.js.map +1 -0
- package/dist/assertion/index.d.ts +2 -0
- package/dist/assertion/index.d.ts.map +1 -0
- package/dist/assertion/index.js +2 -0
- package/dist/assertion/index.js.map +1 -0
- package/dist/assertion/recorder.d.ts +7 -0
- package/dist/assertion/recorder.d.ts.map +1 -0
- package/dist/assertion/recorder.js +81 -0
- package/dist/assertion/recorder.js.map +1 -0
- package/dist/assertion/summarize-recordings.d.ts +3 -0
- package/dist/assertion/summarize-recordings.d.ts.map +1 -0
- package/dist/assertion/summarize-recordings.js +121 -0
- package/dist/assertion/summarize-recordings.js.map +1 -0
- package/dist/assertion/validator.d.ts +2 -0
- package/dist/assertion/validator.d.ts.map +1 -0
- package/dist/assertion/validator.js +3 -0
- package/dist/assertion/validator.js.map +1 -0
- package/dist/base.d.ts +2 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +3 -0
- package/dist/base.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +84 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/extractor/src/lib/child-expansion.d.ts +8 -0
- package/dist/extractor/src/lib/child-expansion.d.ts.map +1 -0
- package/dist/extractor/src/lib/child-expansion.js +72 -0
- package/dist/extractor/src/lib/child-expansion.js.map +1 -0
- package/dist/extractor/src/lib/git.d.ts +9 -0
- package/dist/extractor/src/lib/git.d.ts.map +1 -0
- package/dist/extractor/src/lib/git.js +22 -0
- package/dist/extractor/src/lib/git.js.map +1 -0
- package/dist/extractor/src/lib/schema-flatten.d.ts +10 -0
- package/dist/extractor/src/lib/schema-flatten.d.ts.map +1 -0
- package/dist/extractor/src/lib/schema-flatten.js +203 -0
- package/dist/extractor/src/lib/schema-flatten.js.map +1 -0
- package/dist/extractor/src/lib/type-utils.d.ts +5 -0
- package/dist/extractor/src/lib/type-utils.d.ts.map +1 -0
- package/dist/extractor/src/lib/type-utils.js +27 -0
- package/dist/extractor/src/lib/type-utils.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/assert.d.ts +27 -0
- package/dist/lib/assert.d.ts.map +1 -0
- package/dist/lib/assert.js +32 -0
- package/dist/lib/assert.js.map +1 -0
- package/dist/lib/child-expansion.d.ts +2 -0
- package/dist/lib/child-expansion.d.ts.map +1 -0
- package/dist/lib/child-expansion.js +2 -0
- package/dist/lib/child-expansion.js.map +1 -0
- package/dist/lib/config.d.ts +27 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +139 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/extractor.d.ts +6 -0
- package/dist/lib/extractor.d.ts.map +1 -0
- package/dist/lib/extractor.js +164 -0
- package/dist/lib/extractor.js.map +1 -0
- package/dist/lib/git.d.ts +2 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +2 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/recorder.d.ts +8 -0
- package/dist/lib/recorder.d.ts.map +1 -0
- package/dist/lib/recorder.js +68 -0
- package/dist/lib/recorder.js.map +1 -0
- package/dist/lib/responses.d.ts +13 -0
- package/dist/lib/responses.d.ts.map +1 -0
- package/dist/lib/responses.js +114 -0
- package/dist/lib/responses.js.map +1 -0
- package/dist/lib/schema-flatten.d.ts +2 -0
- package/dist/lib/schema-flatten.d.ts.map +1 -0
- package/dist/lib/schema-flatten.js +2 -0
- package/dist/lib/schema-flatten.js.map +1 -0
- package/dist/lib/tools/diff-recordings-vs-spec.d.ts +2 -0
- package/dist/lib/tools/diff-recordings-vs-spec.d.ts.map +1 -0
- package/dist/lib/tools/diff-recordings-vs-spec.js +2 -0
- package/dist/lib/tools/diff-recordings-vs-spec.js.map +1 -0
- package/dist/lib/tools/recorder.d.ts +2 -0
- package/dist/lib/tools/recorder.d.ts.map +1 -0
- package/dist/lib/tools/recorder.js +3 -0
- package/dist/lib/tools/recorder.js.map +1 -0
- package/dist/lib/tools/summarize-recordings.d.ts +2 -0
- package/dist/lib/tools/summarize-recordings.d.ts.map +1 -0
- package/dist/lib/tools/summarize-recordings.js +2 -0
- package/dist/lib/tools/summarize-recordings.js.map +1 -0
- package/dist/lib/type-utils.d.ts +2 -0
- package/dist/lib/type-utils.d.ts.map +1 -0
- package/dist/lib/type-utils.js +2 -0
- package/dist/lib/type-utils.js.map +1 -0
- package/dist/lib/validator.d.ts +33 -0
- package/dist/lib/validator.d.ts.map +1 -0
- package/dist/lib/validator.js +179 -0
- package/dist/lib/validator.js.map +1 -0
- package/dist/types/index.d.ts +88 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist-cjs/assertion/diff-recordings-vs-spec.d.ts +3 -0
- package/dist-cjs/assertion/diff-recordings-vs-spec.d.ts.map +1 -0
- package/dist-cjs/assertion/diff-recordings-vs-spec.js +178 -0
- package/dist-cjs/assertion/diff-recordings-vs-spec.js.map +1 -0
- package/dist-cjs/assertion/index.d.ts +2 -0
- package/dist-cjs/assertion/index.d.ts.map +1 -0
- package/dist-cjs/assertion/index.js +3 -0
- package/dist-cjs/assertion/index.js.map +1 -0
- package/dist-cjs/assertion/recorder.d.ts +7 -0
- package/dist-cjs/assertion/recorder.d.ts.map +1 -0
- package/dist-cjs/assertion/recorder.js +84 -0
- package/dist-cjs/assertion/recorder.js.map +1 -0
- package/dist-cjs/assertion/summarize-recordings.d.ts +3 -0
- package/dist-cjs/assertion/summarize-recordings.d.ts.map +1 -0
- package/dist-cjs/assertion/summarize-recordings.js +123 -0
- package/dist-cjs/assertion/summarize-recordings.js.map +1 -0
- package/dist-cjs/assertion/validator.d.ts +2 -0
- package/dist-cjs/assertion/validator.d.ts.map +1 -0
- package/dist-cjs/assertion/validator.js +7 -0
- package/dist-cjs/assertion/validator.js.map +1 -0
- package/dist-cjs/base.d.ts +2 -0
- package/dist-cjs/base.d.ts.map +1 -0
- package/dist-cjs/base.js +7 -0
- package/dist-cjs/base.js.map +1 -0
- package/dist-cjs/cli/index.d.ts +3 -0
- package/dist-cjs/cli/index.d.ts.map +1 -0
- package/dist-cjs/cli/index.js +86 -0
- package/dist-cjs/cli/index.js.map +1 -0
- package/dist-cjs/extractor/src/lib/child-expansion.d.ts +8 -0
- package/dist-cjs/extractor/src/lib/child-expansion.d.ts.map +1 -0
- package/dist-cjs/extractor/src/lib/child-expansion.js +76 -0
- package/dist-cjs/extractor/src/lib/child-expansion.js.map +1 -0
- package/dist-cjs/extractor/src/lib/git.d.ts +9 -0
- package/dist-cjs/extractor/src/lib/git.d.ts.map +1 -0
- package/dist-cjs/extractor/src/lib/git.js +26 -0
- package/dist-cjs/extractor/src/lib/git.js.map +1 -0
- package/dist-cjs/extractor/src/lib/schema-flatten.d.ts +10 -0
- package/dist-cjs/extractor/src/lib/schema-flatten.d.ts.map +1 -0
- package/dist-cjs/extractor/src/lib/schema-flatten.js +211 -0
- package/dist-cjs/extractor/src/lib/schema-flatten.js.map +1 -0
- package/dist-cjs/extractor/src/lib/type-utils.d.ts +5 -0
- package/dist-cjs/extractor/src/lib/type-utils.d.ts.map +1 -0
- package/dist-cjs/extractor/src/lib/type-utils.js +32 -0
- package/dist-cjs/extractor/src/lib/type-utils.js.map +1 -0
- package/dist-cjs/index.d.ts +5 -0
- package/dist-cjs/index.d.ts.map +1 -0
- package/dist-cjs/index.js +26 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/lib/assert.d.ts +27 -0
- package/dist-cjs/lib/assert.d.ts.map +1 -0
- package/dist-cjs/lib/assert.js +35 -0
- package/dist-cjs/lib/assert.js.map +1 -0
- package/dist-cjs/lib/child-expansion.d.ts +2 -0
- package/dist-cjs/lib/child-expansion.d.ts.map +1 -0
- package/dist-cjs/lib/child-expansion.js +7 -0
- package/dist-cjs/lib/child-expansion.js.map +1 -0
- package/dist-cjs/lib/config.d.ts +27 -0
- package/dist-cjs/lib/config.d.ts.map +1 -0
- package/dist-cjs/lib/config.js +147 -0
- package/dist-cjs/lib/config.js.map +1 -0
- package/dist-cjs/lib/extractor.d.ts +6 -0
- package/dist-cjs/lib/extractor.d.ts.map +1 -0
- package/dist-cjs/lib/extractor.js +172 -0
- package/dist-cjs/lib/extractor.js.map +1 -0
- package/dist-cjs/lib/git.d.ts +2 -0
- package/dist-cjs/lib/git.d.ts.map +1 -0
- package/dist-cjs/lib/git.js +6 -0
- package/dist-cjs/lib/git.js.map +1 -0
- package/dist-cjs/lib/recorder.d.ts +8 -0
- package/dist-cjs/lib/recorder.d.ts.map +1 -0
- package/dist-cjs/lib/recorder.js +71 -0
- package/dist-cjs/lib/recorder.js.map +1 -0
- package/dist-cjs/lib/responses.d.ts +13 -0
- package/dist-cjs/lib/responses.d.ts.map +1 -0
- package/dist-cjs/lib/responses.js +117 -0
- package/dist-cjs/lib/responses.js.map +1 -0
- package/dist-cjs/lib/schema-flatten.d.ts +2 -0
- package/dist-cjs/lib/schema-flatten.d.ts.map +1 -0
- package/dist-cjs/lib/schema-flatten.js +11 -0
- package/dist-cjs/lib/schema-flatten.js.map +1 -0
- package/dist-cjs/lib/tools/diff-recordings-vs-spec.d.ts +2 -0
- package/dist-cjs/lib/tools/diff-recordings-vs-spec.d.ts.map +1 -0
- package/dist-cjs/lib/tools/diff-recordings-vs-spec.js +18 -0
- package/dist-cjs/lib/tools/diff-recordings-vs-spec.js.map +1 -0
- package/dist-cjs/lib/tools/recorder.d.ts +2 -0
- package/dist-cjs/lib/tools/recorder.d.ts.map +1 -0
- package/dist-cjs/lib/tools/recorder.js +19 -0
- package/dist-cjs/lib/tools/recorder.js.map +1 -0
- package/dist-cjs/lib/tools/summarize-recordings.d.ts +2 -0
- package/dist-cjs/lib/tools/summarize-recordings.d.ts.map +1 -0
- package/dist-cjs/lib/tools/summarize-recordings.js +18 -0
- package/dist-cjs/lib/tools/summarize-recordings.js.map +1 -0
- package/dist-cjs/lib/type-utils.d.ts +2 -0
- package/dist-cjs/lib/type-utils.d.ts.map +1 -0
- package/dist-cjs/lib/type-utils.js +8 -0
- package/dist-cjs/lib/type-utils.js.map +1 -0
- package/dist-cjs/lib/validator.d.ts +33 -0
- package/dist-cjs/lib/validator.d.ts.map +1 -0
- package/dist-cjs/lib/validator.js +182 -0
- package/dist-cjs/lib/validator.js.map +1 -0
- package/dist-cjs/package.json +1 -0
- package/dist-cjs/types/index.d.ts +88 -0
- package/dist-cjs/types/index.d.ts.map +1 -0
- package/dist-cjs/types/index.js +4 -0
- package/dist-cjs/types/index.js.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { FieldSpec } from '../../../types/index.js';
|
|
2
|
+
export declare function normalizeType(t: string): string;
|
|
3
|
+
export declare function refNameOf(t: string): string;
|
|
4
|
+
export declare function dedupeFields(arr: FieldSpec[]): FieldSpec[];
|
|
5
|
+
//# sourceMappingURL=type-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-utils.d.ts","sourceRoot":"","sources":["../../../../src/extractor/src/lib/type-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAW/C;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAmD;AAE/F,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAK1D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function normalizeType(t) {
|
|
2
|
+
if (!t)
|
|
3
|
+
return t;
|
|
4
|
+
if (t.startsWith('string('))
|
|
5
|
+
return 'string';
|
|
6
|
+
t = t.replace(/array<string\([^>]+\)>/g, 'array<string>');
|
|
7
|
+
if (t === 'integer' || /^integer\(/.test(t))
|
|
8
|
+
t = 'number';
|
|
9
|
+
t = t.replace(/\binteger(?:\([^)]*\))?\b/g, 'number');
|
|
10
|
+
t = t.replace(/array<integer(?:\([^>]*\))?>/g, 'array<number>');
|
|
11
|
+
// Collapse formatted numbers produced after integer replacement inside unions or generics
|
|
12
|
+
t = t.replace(/\bnumber\([^)]*\)\b/g, 'number');
|
|
13
|
+
t = t.replace(/array<number\([^>]*\)>/g, 'array<number>');
|
|
14
|
+
return t;
|
|
15
|
+
}
|
|
16
|
+
export function refNameOf(t) { return t.split('<').pop().replace(/>.*/, ''); }
|
|
17
|
+
export function dedupeFields(arr) {
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const f of arr)
|
|
21
|
+
if (!seen.has(f.name)) {
|
|
22
|
+
out.push(f);
|
|
23
|
+
seen.add(f.name);
|
|
24
|
+
}
|
|
25
|
+
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=type-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-utils.js","sourceRoot":"","sources":["../../../../src/extractor/src/lib/type-utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC7C,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,yBAAyB,EAAE,eAAe,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,CAAC,GAAG,QAAQ,CAAC;IAC1D,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,+BAA+B,EAAE,eAAe,CAAC,CAAC;IAChE,0FAA0F;IAC1F,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,yBAAyB,EAAE,eAAe,CAAC,CAAC;IAC1D,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS,IAAY,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAE/F,MAAM,UAAU,YAAY,CAAC,GAAgB;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,GAAG;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;IAC9E,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,EAAE,CAAA,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Framework-agnostic public API surface
|
|
2
|
+
export * from './types/index.js';
|
|
3
|
+
export { pickRoute } from './lib/responses.js';
|
|
4
|
+
export { validateResponseShape } from './lib/validator.js';
|
|
5
|
+
export { recordBody } from './lib/recorder.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAsB,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface AssertionSpec {
|
|
2
|
+
path: string;
|
|
3
|
+
method?: string;
|
|
4
|
+
status?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AssertionOptions {
|
|
7
|
+
/** If false, do not throw; instead return { ok:false, errors } */
|
|
8
|
+
throw?: boolean;
|
|
9
|
+
/** Enable body recording (requires env TEST_RESPONSE_BODY_RECORD_DIR); optional test label */
|
|
10
|
+
record?: boolean | {
|
|
11
|
+
label?: string;
|
|
12
|
+
};
|
|
13
|
+
/** Alternate responses file path (overrides environment resolution) */
|
|
14
|
+
responsesFilePath?: string;
|
|
15
|
+
/** Optional explicit config file path (looked up relative to cwd if relative) */
|
|
16
|
+
configPath?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AssertionResult {
|
|
19
|
+
ok: boolean;
|
|
20
|
+
errors?: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* High-level assertion helper: resolves the route spec entry and validates the given body.
|
|
24
|
+
* Throws by default on mismatch; pass { throw:false } to receive a structured result instead.
|
|
25
|
+
*/
|
|
26
|
+
export declare function assertResponseShape(spec: AssertionSpec, body: unknown, options?: AssertionOptions): AssertionResult | void;
|
|
27
|
+
//# sourceMappingURL=assert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/lib/assert.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AACjF,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAAG,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;AAEnE;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe,GAAG,IAAI,CAoB9H"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { pickRoute } from './responses.js';
|
|
2
|
+
import { recordBody } from './recorder.js';
|
|
3
|
+
import { _validateRouteContext } from './validator.js';
|
|
4
|
+
/**
|
|
5
|
+
* High-level assertion helper: resolves the route spec entry and validates the given body.
|
|
6
|
+
* Throws by default on mismatch; pass { throw:false } to receive a structured result instead.
|
|
7
|
+
*/
|
|
8
|
+
export function assertResponseShape(spec, body, options = {}) {
|
|
9
|
+
const routeCtx = pickRoute(spec.path, { method: spec.method, status: spec.status, responsesFilePath: options.responsesFilePath, configPath: options.configPath });
|
|
10
|
+
const wantRecord = !!options.record;
|
|
11
|
+
if (wantRecord) {
|
|
12
|
+
let label;
|
|
13
|
+
if (typeof options.record === 'object' && options.record)
|
|
14
|
+
label = options.record.label;
|
|
15
|
+
recordBody({ routeCtx, body, label });
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
_validateRouteContext(routeCtx, body);
|
|
19
|
+
if (options.throw === false)
|
|
20
|
+
return { ok: true };
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (options.throw === false) {
|
|
24
|
+
const msg = err.message || '';
|
|
25
|
+
// first line is summary; retain full message lines after summary for detail
|
|
26
|
+
const lines = msg.split('\n');
|
|
27
|
+
return { ok: false, errors: lines.slice(1).filter(Boolean) };
|
|
28
|
+
}
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=assert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../../src/lib/assert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAiBvD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAmB,EAAE,IAAa,EAAE,UAA4B,EAAE;IACpG,MAAM,QAAQ,GAAiB,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAChL,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACpC,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,KAAyB,CAAC;QAC9B,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACvF,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,CAAC;QACL,qBAAqB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAI,GAAa,CAAC,OAAO,IAAI,EAAE,CAAC;YACzC,4EAA4E;YAC5E,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/D,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-expansion.d.ts","sourceRoot":"","sources":["../../src/lib/child-expansion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-expansion.js","sourceRoot":"","sources":["../../src/lib/child-expansion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ExtractConfig, ValidateConfig, ConfigFile, ConfigResolution, ResolvedConfig } from '../types/index.js';
|
|
2
|
+
export declare function loadConfigFile(cwd?: string, explicitPath?: string): {
|
|
3
|
+
filePath?: string;
|
|
4
|
+
file?: ConfigFile;
|
|
5
|
+
error?: Error;
|
|
6
|
+
};
|
|
7
|
+
export declare function parseCliArgs(argv?: string[]): {
|
|
8
|
+
command?: string;
|
|
9
|
+
args: Record<string, string | boolean>;
|
|
10
|
+
positionals: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare function cliConfigSubset(raw: Record<string, string | boolean>): ExtractConfig;
|
|
13
|
+
export declare function envConfigSubset(env?: NodeJS.ProcessEnv): {
|
|
14
|
+
extract: ExtractConfig;
|
|
15
|
+
validate: ValidateConfig;
|
|
16
|
+
};
|
|
17
|
+
export declare function resolveConfig(parts: {
|
|
18
|
+
file?: ConfigFile;
|
|
19
|
+
cli: ExtractConfig;
|
|
20
|
+
env: {
|
|
21
|
+
extract: ExtractConfig;
|
|
22
|
+
validate: ValidateConfig;
|
|
23
|
+
};
|
|
24
|
+
warnings: string[];
|
|
25
|
+
}): ResolvedConfig;
|
|
26
|
+
export declare function buildConfig(explicitConfigPath?: string): ConfigResolution;
|
|
27
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAiD,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAqB/J,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAU1I;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAC,MAAM,GAAC,OAAO,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAiBrJ;AAQD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAC,MAAM,GAAC,OAAO,CAAC,GAAG,aAAa,CAEjF;AAED,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,CAoB1H;AAaD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAA;KAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,cAAc,CAoB7K;AAED,wBAAgB,WAAW,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAUzE"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
const CONFIG_FILENAME = 'assert-json-body.config.json';
|
|
5
|
+
const DEFAULT_EXTRACT = {
|
|
6
|
+
repo: 'https://github.com/camunda/camunda-orchestration-cluster-api',
|
|
7
|
+
specPath: 'specification/rest-api.yaml',
|
|
8
|
+
ref: 'main',
|
|
9
|
+
outputDir: 'assert-json-body',
|
|
10
|
+
preserveCheckout: false,
|
|
11
|
+
dryRun: false,
|
|
12
|
+
logLevel: 'info',
|
|
13
|
+
failIfExists: false,
|
|
14
|
+
responsesFile: undefined,
|
|
15
|
+
};
|
|
16
|
+
const DEFAULT_VALIDATE = {
|
|
17
|
+
recordResponses: false,
|
|
18
|
+
throwOnValidationFail: true,
|
|
19
|
+
};
|
|
20
|
+
export function loadConfigFile(cwd = process.cwd(), explicitPath) {
|
|
21
|
+
const path = explicitPath ? resolve(cwd, explicitPath) : resolve(cwd, CONFIG_FILENAME);
|
|
22
|
+
if (!existsSync(path))
|
|
23
|
+
return {};
|
|
24
|
+
try {
|
|
25
|
+
const raw = readFileSync(path, 'utf8');
|
|
26
|
+
const parsed = JSON.parse(raw);
|
|
27
|
+
return { filePath: path, file: parsed };
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
return { error: err };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function parseCliArgs(argv = process.argv.slice(2)) {
|
|
34
|
+
const args = {};
|
|
35
|
+
const positionals = [];
|
|
36
|
+
let command;
|
|
37
|
+
for (const token of argv) {
|
|
38
|
+
if (!command && !token.startsWith('-')) {
|
|
39
|
+
command = token;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (token.startsWith('--')) {
|
|
43
|
+
const [k, v] = token.slice(2).split('=');
|
|
44
|
+
if (v === undefined)
|
|
45
|
+
args[k] = true;
|
|
46
|
+
else
|
|
47
|
+
args[k] = v;
|
|
48
|
+
}
|
|
49
|
+
else if (token.startsWith('-')) {
|
|
50
|
+
const flags = token.slice(1).split('');
|
|
51
|
+
for (const f of flags)
|
|
52
|
+
args[f] = true;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
positionals.push(token);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { command, args, positionals };
|
|
59
|
+
}
|
|
60
|
+
function pick(obj, keys) {
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const k of keys)
|
|
63
|
+
if (k in obj)
|
|
64
|
+
out[k] = obj[k];
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
export function cliConfigSubset(raw) {
|
|
68
|
+
return pick(raw, ['repo', 'specPath', 'ref', 'outputDir', 'preserveCheckout', 'dryRun', 'responsesFile', 'logLevel', 'failIfExists']);
|
|
69
|
+
}
|
|
70
|
+
export function envConfigSubset(env = process.env) {
|
|
71
|
+
const map = {};
|
|
72
|
+
for (const [k, v] of Object.entries(env))
|
|
73
|
+
if (typeof v === 'string')
|
|
74
|
+
map[k] = v;
|
|
75
|
+
const getBool = (k) => map[k] ? /^(1|true|yes)$/i.test(map[k]) : undefined;
|
|
76
|
+
const extract = {
|
|
77
|
+
repo: map.AJB_REPO || map.REPO,
|
|
78
|
+
specPath: map.AJB_SPEC_PATH || map.SPEC_PATH,
|
|
79
|
+
ref: map.AJB_REF || map.SPEC_REF || map.REF,
|
|
80
|
+
outputDir: map.AJB_OUTPUT_DIR || map.OUTPUT_DIR,
|
|
81
|
+
preserveCheckout: getBool('AJB_PRESERVE_CHECKOUT') ?? getBool('PRESERVE_SPEC_CHECKOUT'),
|
|
82
|
+
dryRun: getBool('AJB_DRY_RUN'),
|
|
83
|
+
responsesFile: map.AJB_RESPONSES_FILE || map.ROUTE_TEST_RESPONSES_FILE,
|
|
84
|
+
logLevel: map.AJB_LOG_LEVEL || undefined,
|
|
85
|
+
failIfExists: getBool('AJB_FAIL_IF_EXISTS'),
|
|
86
|
+
};
|
|
87
|
+
const validate = {
|
|
88
|
+
recordResponses: getBool('AJB_RECORD') ?? getBool('TEST_RESPONSE_BODY_RECORD'),
|
|
89
|
+
throwOnValidationFail: getBool('AJB_THROW_ON_FAIL'),
|
|
90
|
+
};
|
|
91
|
+
return { extract, validate };
|
|
92
|
+
}
|
|
93
|
+
function coerceExtract(config, warnings) {
|
|
94
|
+
if (typeof config.preserveCheckout === 'string')
|
|
95
|
+
config.preserveCheckout = /^(1|true|yes)$/i.test(config.preserveCheckout);
|
|
96
|
+
if (typeof config.dryRun === 'string')
|
|
97
|
+
config.dryRun = /^(1|true|yes)$/i.test(config.dryRun);
|
|
98
|
+
if (typeof config.failIfExists === 'string')
|
|
99
|
+
config.failIfExists = /^(1|true|yes)$/i.test(config.failIfExists);
|
|
100
|
+
if (config.logLevel && !['silent', 'error', 'warn', 'info', 'debug'].includes(config.logLevel)) {
|
|
101
|
+
warnings.push(`Unknown logLevel '${config.logLevel}', falling back to 'info'`);
|
|
102
|
+
config.logLevel = 'info';
|
|
103
|
+
}
|
|
104
|
+
return config;
|
|
105
|
+
}
|
|
106
|
+
export function resolveConfig(parts) {
|
|
107
|
+
const mergedExtract = { ...DEFAULT_EXTRACT, ...(parts.file?.extract || {}), ...parts.cli, ...parts.env.extract };
|
|
108
|
+
const mergedValidate = { ...DEFAULT_VALIDATE, ...(parts.file?.validate || {}), ...parts.env.validate };
|
|
109
|
+
coerceExtract(mergedExtract, parts.warnings);
|
|
110
|
+
const extract = {
|
|
111
|
+
repo: mergedExtract.repo || DEFAULT_EXTRACT.repo,
|
|
112
|
+
specPath: mergedExtract.specPath || DEFAULT_EXTRACT.specPath,
|
|
113
|
+
ref: mergedExtract.ref || DEFAULT_EXTRACT.ref,
|
|
114
|
+
outputDir: mergedExtract.outputDir || DEFAULT_EXTRACT.outputDir,
|
|
115
|
+
preserveCheckout: mergedExtract.preserveCheckout ?? DEFAULT_EXTRACT.preserveCheckout,
|
|
116
|
+
dryRun: mergedExtract.dryRun ?? DEFAULT_EXTRACT.dryRun,
|
|
117
|
+
logLevel: mergedExtract.logLevel || DEFAULT_EXTRACT.logLevel,
|
|
118
|
+
failIfExists: mergedExtract.failIfExists ?? DEFAULT_EXTRACT.failIfExists,
|
|
119
|
+
responsesFile: mergedExtract.responsesFile,
|
|
120
|
+
};
|
|
121
|
+
const validate = {
|
|
122
|
+
recordResponses: mergedValidate.recordResponses ?? DEFAULT_VALIDATE.recordResponses,
|
|
123
|
+
throwOnValidationFail: mergedValidate.throwOnValidationFail ?? DEFAULT_VALIDATE.throwOnValidationFail,
|
|
124
|
+
};
|
|
125
|
+
return { extract, validate };
|
|
126
|
+
}
|
|
127
|
+
export function buildConfig(explicitConfigPath) {
|
|
128
|
+
const warnings = [];
|
|
129
|
+
const { filePath, file, error } = loadConfigFile(process.cwd(), explicitConfigPath);
|
|
130
|
+
if (error)
|
|
131
|
+
warnings.push(`Failed to load config file: ${error.message}`);
|
|
132
|
+
const { args } = parseCliArgs();
|
|
133
|
+
// only parse config impacting args
|
|
134
|
+
const cli = cliConfigSubset(args);
|
|
135
|
+
const env = envConfigSubset();
|
|
136
|
+
const resolved = resolveConfig({ file, cli, env, warnings });
|
|
137
|
+
return { filePath, file, cli, env, resolved, warnings };
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
import { ResponseEntry, SchemaGroup, ExtractConfig } from '../types/index.js';
|
|
3
|
+
export declare function extractResponses(doc: OpenAPIV3.Document): ResponseEntry[];
|
|
4
|
+
export declare function pruneSchema(schema: SchemaGroup): void;
|
|
5
|
+
export declare function generate(cfg?: ExtractConfig): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/lib/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAiB,aAAa,EAAE,WAAW,EAAE,aAAa,EAAyB,MAAM,mBAAmB,CAAC;AAmBpH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,GAAG,aAAa,EAAE,CAoBzE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,QAc9C;AAED,wBAAsB,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,iBA4EjD"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import yaml from 'js-yaml';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { sparseCheckout } from './git.js';
|
|
7
|
+
import { buildSchemaTree } from './child-expansion.js';
|
|
8
|
+
import { buildConfig } from './config.js';
|
|
9
|
+
function isRef(obj) {
|
|
10
|
+
return !!obj && typeof obj === 'object' && '$ref' in obj;
|
|
11
|
+
}
|
|
12
|
+
function resolveResponse(resp, doc) {
|
|
13
|
+
if (isRef(resp)) {
|
|
14
|
+
const refName = resp.$ref.split('/').pop();
|
|
15
|
+
return doc.components?.responses?.[refName] || resp;
|
|
16
|
+
}
|
|
17
|
+
return resp;
|
|
18
|
+
}
|
|
19
|
+
export function extractResponses(doc) {
|
|
20
|
+
const entries = [];
|
|
21
|
+
const paths = (doc.paths || {});
|
|
22
|
+
for (const [path, pathItem] of Object.entries(paths)) {
|
|
23
|
+
for (const method of ['get', 'post', 'put', 'patch', 'delete']) {
|
|
24
|
+
const op = pathItem[method];
|
|
25
|
+
if (!op)
|
|
26
|
+
continue;
|
|
27
|
+
const responses = (op.responses || {});
|
|
28
|
+
for (const [status, response] of Object.entries(responses)) {
|
|
29
|
+
const resolved = resolveResponse(response, doc);
|
|
30
|
+
const content = resolved.content;
|
|
31
|
+
const appJson = content?.['application/json'];
|
|
32
|
+
const schema = appJson?.schema;
|
|
33
|
+
if (!schema)
|
|
34
|
+
continue;
|
|
35
|
+
const flattened = buildSchemaTree(schema, (doc.components?.schemas || {}));
|
|
36
|
+
entries.push({ path, method: method.toUpperCase(), status, schema: { required: flattened.required, optional: flattened.optional } });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return entries;
|
|
41
|
+
}
|
|
42
|
+
export function pruneSchema(schema) {
|
|
43
|
+
const visit = (sch) => {
|
|
44
|
+
for (const group of [sch.required, sch.optional]) {
|
|
45
|
+
for (const field of group) {
|
|
46
|
+
if (field.children) {
|
|
47
|
+
visit(field.children);
|
|
48
|
+
if (field.children.required.length === 0 && field.children.optional.length === 0) {
|
|
49
|
+
delete field.children;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
visit(schema);
|
|
56
|
+
}
|
|
57
|
+
export async function generate(cfg) {
|
|
58
|
+
// Resolve configuration (allows direct call with partial overrides)
|
|
59
|
+
const resolution = buildConfig();
|
|
60
|
+
const base = resolution.resolved.extract;
|
|
61
|
+
const effective = {
|
|
62
|
+
repo: cfg?.repo || base.repo,
|
|
63
|
+
specPath: cfg?.specPath || base.specPath,
|
|
64
|
+
ref: cfg?.ref || base.ref,
|
|
65
|
+
outputDir: cfg?.outputDir || base.outputDir,
|
|
66
|
+
preserveCheckout: cfg?.preserveCheckout ?? base.preserveCheckout,
|
|
67
|
+
dryRun: cfg?.dryRun ?? base.dryRun,
|
|
68
|
+
logLevel: cfg?.logLevel || base.logLevel,
|
|
69
|
+
failIfExists: cfg?.failIfExists ?? base.failIfExists,
|
|
70
|
+
responsesFile: cfg?.responsesFile || base.responsesFile,
|
|
71
|
+
};
|
|
72
|
+
const REPO = effective.repo;
|
|
73
|
+
const SPEC_PATH = effective.specPath;
|
|
74
|
+
const { workdir, commit, specContent } = sparseCheckout(REPO, SPEC_PATH, effective.ref);
|
|
75
|
+
try {
|
|
76
|
+
const raw = yaml.load(specContent);
|
|
77
|
+
// We accept partial docs; cast to OpenAPIV3.Document for extraction purposes.
|
|
78
|
+
const doc = raw;
|
|
79
|
+
const responses = extractResponses(doc);
|
|
80
|
+
for (const entry of responses)
|
|
81
|
+
pruneSchema(entry.schema);
|
|
82
|
+
const sha256 = crypto.createHash('sha256').update(specContent).digest('hex');
|
|
83
|
+
const out = { metadata: { sourceRepo: REPO, commit, generatedAt: new Date().toISOString(), specPath: SPEC_PATH, specSha256: sha256 }, responses };
|
|
84
|
+
const outDir = effective.outputDir;
|
|
85
|
+
const targetFile = effective.responsesFile ? resolve(effective.responsesFile) : join(outDir, 'responses.json');
|
|
86
|
+
if (effective.failIfExists && existsSync(targetFile)) {
|
|
87
|
+
throw new Error(`Target file already exists: ${targetFile}`);
|
|
88
|
+
}
|
|
89
|
+
if (!effective.dryRun) {
|
|
90
|
+
mkdirSync(outDir, { recursive: true });
|
|
91
|
+
writeFileSync(targetFile, JSON.stringify(out, null, 2));
|
|
92
|
+
// Emit TypeScript index.ts with strongly-typed validateResponseShape wrapper
|
|
93
|
+
try {
|
|
94
|
+
const routeIndex = {};
|
|
95
|
+
for (const r of responses) {
|
|
96
|
+
if (!routeIndex[r.path])
|
|
97
|
+
routeIndex[r.path] = {};
|
|
98
|
+
if (!routeIndex[r.path][r.method])
|
|
99
|
+
routeIndex[r.path][r.method] = {};
|
|
100
|
+
routeIndex[r.path][r.method][r.status] = 1;
|
|
101
|
+
}
|
|
102
|
+
const indexSource = `/* Auto-generated by assert-json-body extract. Do not edit manually. */\n` +
|
|
103
|
+
`import { validateResponseShape as _baseValidateResponseShape } from 'assert-json-body/base';\n\n` +
|
|
104
|
+
`export const RESPONSE_INDEX = ${JSON.stringify(routeIndex, null, 2)} as const;\n\n` +
|
|
105
|
+
`export type RoutePath = keyof typeof RESPONSE_INDEX;\n` +
|
|
106
|
+
`export type MethodFor<P extends RoutePath> = Extract<keyof typeof RESPONSE_INDEX[P], string>;\n` +
|
|
107
|
+
`export type StatusFor<P extends RoutePath, M extends MethodFor<P>> = Extract<keyof typeof RESPONSE_INDEX[P][M], string>;\n\n` +
|
|
108
|
+
`export interface TypedRouteSpec<P extends RoutePath = RoutePath, M extends MethodFor<P> = MethodFor<P>, S extends StatusFor<P, M> = StatusFor<P, M>> {\n` +
|
|
109
|
+
` path: P;\n method: M;\n status: S;\n}` + '\n\n' +
|
|
110
|
+
`export function validateResponseShape<P extends RoutePath, M extends MethodFor<P>, S extends StatusFor<P,M>>(spec: { path: P; method: M; status: S }, body: unknown, options?: { responsesFilePath?: string; configPath?: string; throw?: boolean; record?: boolean | { label?: string } }) {\n` +
|
|
111
|
+
` // Cast to base signature (method/status widened to string) for internal call.\n` +
|
|
112
|
+
` const baseFn: any = _baseValidateResponseShape;\n` +
|
|
113
|
+
` if (baseFn === (validateResponseShape as any)) {\n` +
|
|
114
|
+
` throw new Error(
|
|
115
|
+
"Typed validator resolved to itself. Avoid aliasing the package name to the generated typed file. Use a relative import to the generated ./assert-json-body/index or import from 'assert-json-body/base' for the core API."
|
|
116
|
+
);\n` +
|
|
117
|
+
` }\n` +
|
|
118
|
+
` return baseFn(spec as unknown as { path: string; method?: string; status?: string }, body, options);\n}` + '\n';
|
|
119
|
+
writeFileSync(join(outDir, 'index.ts'), indexSource);
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
if (effective.logLevel === 'debug')
|
|
123
|
+
console.warn('Failed to emit typed index.ts:', e.message);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (effective.logLevel !== 'silent') {
|
|
127
|
+
console.log(`Extracted ${responses.length} response schemas from commit ${commit}` + (effective.dryRun ? ' (dry-run: no files written)' : ''));
|
|
128
|
+
if (effective.responsesFile && effective.logLevel === 'debug') {
|
|
129
|
+
console.log(`Responses file explicit: ${targetFile}`);
|
|
130
|
+
}
|
|
131
|
+
if (resolution.warnings.length) {
|
|
132
|
+
for (const w of resolution.warnings)
|
|
133
|
+
console.warn(`[config] ${w}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
if (effective.preserveCheckout) {
|
|
139
|
+
if (effective.logLevel === 'debug')
|
|
140
|
+
console.log('Preserving temporary spec checkout.');
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
try {
|
|
144
|
+
rmSync(workdir, { recursive: true, force: true });
|
|
145
|
+
}
|
|
146
|
+
catch { /* ignore cleanup error */ }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Runtime main guard (ESM safe). For CJS compiled output we skip auto-exec to avoid import.meta requirement.
|
|
151
|
+
try {
|
|
152
|
+
// Access import.meta.url only in ESM environments.
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
const thisUrl = typeof import.meta !== 'undefined' ? import.meta.url : undefined;
|
|
156
|
+
if (thisUrl) {
|
|
157
|
+
const isMain = process.argv[1] && fileURLToPath(thisUrl) === process.argv[1];
|
|
158
|
+
if (isMain) {
|
|
159
|
+
generate();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch { /* ignore */ }
|
|
164
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/lib/extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/lib/git.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/lib/recorder.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAe/C,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAAE,GAAG,IAAI,CA6CrH"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
2
|
+
const RECORD_DIR = process.env.TEST_RESPONSE_BODY_RECORD_DIR;
|
|
3
|
+
function ensureRecordDir() {
|
|
4
|
+
if (!RECORD_DIR)
|
|
5
|
+
return;
|
|
6
|
+
if (!existsSync(RECORD_DIR)) {
|
|
7
|
+
try {
|
|
8
|
+
mkdirSync(RECORD_DIR, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
catch { /* ignore */ }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function sanitizeForFile(name) {
|
|
14
|
+
return name.replace(/^\//, '').replace(/[^A-Za-z0-9._-]+/g, '_');
|
|
15
|
+
}
|
|
16
|
+
export function recordBody(opts) {
|
|
17
|
+
if (!RECORD_DIR)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
ensureRecordDir();
|
|
21
|
+
const { routeCtx, body } = opts;
|
|
22
|
+
const testTitle = opts.testTitle || opts.label;
|
|
23
|
+
const fileBase = `${(routeCtx.method || 'ANY').toUpperCase()}_${routeCtx.status || 'ANY'}_${sanitizeForFile(routeCtx.route)}`;
|
|
24
|
+
const file = `${RECORD_DIR}/${fileBase}.jsonl`;
|
|
25
|
+
const present = [];
|
|
26
|
+
const deepSet = new Set();
|
|
27
|
+
const isObj = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
28
|
+
const escape = (seg) => seg.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
29
|
+
const addPath = (p) => { if (p)
|
|
30
|
+
deepSet.add(p); };
|
|
31
|
+
const walk = (val, base) => {
|
|
32
|
+
if (isObj(val)) {
|
|
33
|
+
for (const key of Object.keys(val)) {
|
|
34
|
+
const ptr = `${base}/${escape(key)}`;
|
|
35
|
+
addPath(ptr);
|
|
36
|
+
walk(val[key], ptr);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (Array.isArray(val)) {
|
|
40
|
+
for (let i = 0; i < val.length; i++) {
|
|
41
|
+
const el = val[i];
|
|
42
|
+
if (isObj(el) || Array.isArray(el))
|
|
43
|
+
walk(el, `${base}/*`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
if (isObj(body)) {
|
|
48
|
+
for (const k of Object.keys(body))
|
|
49
|
+
present.push(k);
|
|
50
|
+
walk(body, '');
|
|
51
|
+
}
|
|
52
|
+
const deepPresent = Array.from(deepSet).sort();
|
|
53
|
+
const line = JSON.stringify({
|
|
54
|
+
ts: new Date().toISOString(),
|
|
55
|
+
route: routeCtx.route,
|
|
56
|
+
method: routeCtx.method,
|
|
57
|
+
status: routeCtx.status,
|
|
58
|
+
test: testTitle,
|
|
59
|
+
required: routeCtx.requiredFieldNames,
|
|
60
|
+
present,
|
|
61
|
+
deepPresent,
|
|
62
|
+
body,
|
|
63
|
+
});
|
|
64
|
+
appendFileSync(file, line + '\n');
|
|
65
|
+
}
|
|
66
|
+
catch { /* ignore */ }
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/lib/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAG9D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;AAE7D,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YAAC,SAAS,CAAC,UAAU,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAoF;IAC7G,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,CAAC;QACH,eAAe,EAAE,CAAC;QACpB,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAC,GAAG,IAAI,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC;QAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,IAAI,QAAQ,CAAC,MAAM,IAAI,KAAK,IAAI,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9H,MAAM,IAAI,GAAG,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;QAC/C,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,CAAU,EAAgC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9G,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,GAAG,IAAI,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,IAAI,GAAG,CAAC,GAAY,EAAE,IAAY,EAAE,EAAE;YAC1C,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACf,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;oBACrC,OAAO,CAAC,GAAG,CAAC,CAAC;oBACb,IAAI,CAAE,GAA+B,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACpC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;oBAChB,IAAI,KAAK,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;wBAAE,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAChB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnD,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,QAAQ,CAAC,kBAAkB;YACrC,OAAO;YACP,WAAW;YACX,IAAI;SACL,CAAC,CAAC;QACH,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;AAC1B,CAAC"}
|