Skip to content

Commit f02085c

Browse files
committed
Compile request
1 parent 0ed021e commit f02085c

16 files changed

+274
-143
lines changed

bun.lockb

362 Bytes
Binary file not shown.

package.json

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
{
2-
"name": "openapi-to-validate",
3-
"version": "0.0.0",
4-
"description": "Compile an OpenAPI file to a JS validation function for requests",
5-
"main": "index.js",
6-
"scripts": {
7-
"test": "bun test",
8-
"format": "prettier ./ --ignore-unknown --write"
9-
},
10-
"author": "",
11-
"license": "ISC",
12-
"dependencies": {
13-
"ast-types": "^0.14.2",
14-
"escodegen": "^2.1.0",
15-
"hash-object": "^0.1.7"
16-
},
17-
"devDependencies": {
18-
"@types/escodegen": "^0.0.9",
19-
"prettier": "^3.0.3"
20-
}
2+
"name": "openapi-to-validate",
3+
"version": "0.0.0",
4+
"description": "Compile an OpenAPI file to a JS validation function for requests",
5+
"main": "index.js",
6+
"type": "module",
7+
"scripts": {
8+
"test": "bun test",
9+
"format": "prettier ./ --ignore-unknown --write"
10+
},
11+
"author": "",
12+
"license": "ISC",
13+
"dependencies": {
14+
"ast-types": "^0.14.2",
15+
"escodegen": "^2.1.0",
16+
"hash-object": "^0.1.7",
17+
"path-to-regexp": "^6.2.1"
18+
},
19+
"devDependencies": {
20+
"@types/escodegen": "^0.0.9",
21+
"prettier": "^3.0.3"
22+
}
2123
}

run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Compiler } from "./src";
1+
import { Compiler } from './src';
22

33
const spec = require('./openapi.all.json');
44
const compiler = new Compiler(spec);
55
compiler.build();
6-
console.log(compiler.compile());
6+
console.log(compiler.compile());

src/compileOperation.ts

Lines changed: 64 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { namedTypes, builders } from 'ast-types';
22

3-
import { Compiler } from "./compiler";
4-
import { OpenAPIOperation } from "./types";
3+
import { Compiler } from './compiler';
4+
import { OpenAPIOperation } from './types';
55
import { compileValueSchema } from './compileValueSchema';
66
import { ValidationErrorIdentifier } from './error';
77

@@ -20,23 +20,32 @@ export function compileOperation(compiler: Compiler, operation: OpenAPIOperation
2020
return compiler.defineValidationFunction(operation, ({ value, path, error }) => {
2121
const nodes: namedTypes.BlockStatement['body'] = [];
2222

23+
if (operation.operationId) {
24+
nodes.push(
25+
builders.expressionStatement(
26+
builders.assignmentExpression(
27+
'=',
28+
builders.memberExpression(value, builders.identifier('operationId')),
29+
builders.literal(operation.operationId),
30+
),
31+
),
32+
);
33+
}
34+
2335
if (operation.requestBody) {
2436
if (operation.requestBody.required) {
25-
nodes.push(builders.ifStatement(
26-
builders.binaryExpression(
27-
'===',
28-
builders.memberExpression(
29-
value,
30-
builders.identifier('body'),
37+
nodes.push(
38+
builders.ifStatement(
39+
builders.binaryExpression(
40+
'===',
41+
builders.memberExpression(value, builders.identifier('body')),
42+
builders.identifier('undefined'),
3143
),
32-
builders.identifier('undefined'),
44+
builders.blockStatement([
45+
builders.returnStatement(error('body is required')),
46+
]),
3347
),
34-
builders.blockStatement([
35-
builders.returnStatement(
36-
error('body is required')
37-
),
38-
]),
39-
));
48+
);
4049
}
4150

4251
const contentTypeSchema = operation.requestBody.content?.['application/json']?.schema;
@@ -45,73 +54,56 @@ export function compileOperation(compiler: Compiler, operation: OpenAPIOperation
4554
const bodyResult = builders.identifier('body');
4655

4756
nodes.push(
48-
builders.variableDeclaration(
49-
'const',
50-
[
51-
builders.variableDeclarator(
52-
bodyResult,
53-
builders.callExpression(bodyFn, [
54-
builders.arrayExpression([
55-
builders.spreadElement(path),
56-
builders.literal('body'),
57-
]),
58-
builders.memberExpression(
59-
value,
60-
builders.identifier('body'),
61-
),
57+
builders.variableDeclaration('const', [
58+
builders.variableDeclarator(
59+
bodyResult,
60+
builders.callExpression(bodyFn, [
61+
builders.arrayExpression([
62+
builders.spreadElement(path),
63+
builders.literal('body'),
6264
]),
63-
)
64-
]
65-
)
65+
builders.memberExpression(value, builders.identifier('body')),
66+
]),
67+
),
68+
]),
6669
);
6770

68-
nodes.push(builders.ifStatement(
69-
builders.binaryExpression(
70-
'instanceof',
71-
bodyResult,
72-
ValidationErrorIdentifier,
73-
),
74-
builders.blockStatement([
75-
builders.returnStatement(bodyResult),
76-
]),
77-
builders.blockStatement([
78-
builders.expressionStatement(
79-
builders.assignmentExpression(
80-
'=',
81-
builders.memberExpression(
82-
value,
83-
builders.identifier('body'),
71+
nodes.push(
72+
builders.ifStatement(
73+
builders.binaryExpression(
74+
'instanceof',
75+
bodyResult,
76+
ValidationErrorIdentifier,
77+
),
78+
builders.blockStatement([builders.returnStatement(bodyResult)]),
79+
builders.blockStatement([
80+
builders.expressionStatement(
81+
builders.assignmentExpression(
82+
'=',
83+
builders.memberExpression(value, builders.identifier('body')),
84+
bodyResult,
8485
),
85-
bodyResult,
86-
)
87-
)
88-
])
89-
));
86+
),
87+
]),
88+
),
89+
);
9090
}
9191
} else {
92-
nodes.push(builders.ifStatement(
93-
builders.binaryExpression(
94-
'!==',
95-
builders.memberExpression(
96-
value,
97-
builders.identifier('body'),
92+
nodes.push(
93+
builders.ifStatement(
94+
builders.binaryExpression(
95+
'!==',
96+
builders.memberExpression(value, builders.identifier('body')),
97+
builders.identifier('undefined'),
9898
),
99-
builders.identifier('undefined'),
99+
builders.blockStatement([
100+
builders.returnStatement(error('body is not allowed')),
101+
]),
100102
),
101-
builders.blockStatement([
102-
builders.returnStatement(
103-
error('body is not allowed')
104-
),
105-
]),
106-
));
103+
);
107104
}
108105

109-
nodes.push(
110-
builders.returnStatement(
111-
value
112-
)
113-
)
114-
106+
nodes.push(builders.returnStatement(value));
115107

116108
return nodes;
117109
});

src/compileParameter.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { namedTypes, builders } from 'ast-types';
2+
3+
import { Compiler } from './compiler';
4+
import { OpenAPIParameter } from './types';
5+
import { compileValueSchema } from './compileValueSchema';
6+
7+
/**
8+
* Compile a parameter into a validation function.
9+
* The value input is an object:
10+
* {
11+
* path: string;
12+
* params: Record<string, string>;
13+
* method: string;
14+
* body: any;
15+
* query: Record<string, string>;
16+
* headers: any;
17+
* }
18+
*/
19+
export function compileParameter(compiler: Compiler, parameter: OpenAPIParameter) {
20+
return compiler.defineValidationFunction(parameter, ({ value, path, error }) => {
21+
const nodes: namedTypes.BlockStatement['body'] = [];
22+
23+
const paramValue = builders.memberExpression(
24+
value,
25+
parameter.in === 'path' ? builders.literal('params') : builders.literal('query'),
26+
true,
27+
);
28+
29+
if (parameter.required) {
30+
nodes.push(
31+
builders.ifStatement(
32+
builders.binaryExpression('===', paramValue, builders.identifier('undefined')),
33+
builders.blockStatement([
34+
builders.returnStatement(error('parameter is required')),
35+
]),
36+
),
37+
);
38+
}
39+
40+
const schemaFn = compileValueSchema(compiler, parameter.schema);
41+
42+
nodes.push(
43+
builders.variableDeclaration('const', [
44+
builders.variableDeclarator(
45+
builders.identifier('result'),
46+
builders.callExpression(schemaFn, [path, paramValue]),
47+
),
48+
]),
49+
);
50+
51+
nodes.push(builders.returnStatement(value));
52+
53+
return nodes;
54+
});
55+
}

src/compilePath.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { namedTypes, builders } from 'ast-types';
22

3-
import { Compiler } from "./compiler";
4-
import { OpenAPIPath } from "./types";
5-
import { compileValueSchema } from './compileValueSchema';
6-
import { ValidationErrorIdentifier } from './error';
3+
import { Compiler } from './compiler';
4+
import { OpenAPIPath } from './types';
75
import { compileOperation } from './compileOperation';
86

97
/**
@@ -28,29 +26,19 @@ export function compilePath(compiler: Compiler, pathOperations: OpenAPIPath) {
2826
builders.ifStatement(
2927
builders.binaryExpression(
3028
'===',
31-
builders.memberExpression(
32-
value,
33-
builders.identifier('method'),
34-
),
29+
builders.memberExpression(value, builders.identifier('method')),
3530
builders.literal(method),
3631
),
3732
builders.blockStatement([
3833
builders.returnStatement(
39-
builders.callExpression(fnOperation, [
40-
path,
41-
value,
42-
]),
34+
builders.callExpression(fnOperation, [path, value]),
4335
),
4436
]),
45-
)
46-
)
37+
),
38+
);
4739
});
4840

49-
nodes.push(
50-
builders.returnStatement(
51-
error('method not supported')
52-
),
53-
)
41+
nodes.push(builders.returnStatement(error('method not supported')));
5442

5543
return nodes;
5644
});

0 commit comments

Comments
 (0)