Skip to content

Commit 8d849ef

Browse files
committed
Better setup repository
1 parent 8344fb1 commit 8d849ef

24 files changed

+409
-387
lines changed

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1+
# System
2+
.DS_Store
3+
4+
# Node
15
node_modules/
6+
7+
# Tests
8+
tests/*.validate.js
9+
*.tsbuildinfo
10+
11+
# Output
12+
dist/

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ CLI to compile an OpenAPI specification as JavaScript validation file, optimized
44

55
## TODOs
66

7-
- Path/Operations
8-
- [ ] Validate parameters
9-
- JSONSchema `string` validation of:
10-
- [x] `minLength`
11-
- [x] `maxLength`
12-
- [ ] `format`
13-
- [x] `pattern`
14-
- JSONSchema `array` validation of:
15-
- [x] `minItems`
16-
- [x] `maxItems`
17-
- [x] `uniqueItems`
18-
- JSONSchema `integer`
19-
- [ ] no float
7+
- Path/Operations
8+
- [ ] Validate parameters
9+
- JSONSchema `string` validation of:
10+
- [x] `minLength`
11+
- [x] `maxLength`
12+
- [ ] `format`
13+
- [x] `pattern`
14+
- JSONSchema `array` validation of:
15+
- [x] `minItems`
16+
- [x] `maxItems`
17+
- [x] `uniqueItems`
18+
- JSONSchema `integer`
19+
- [ ] no float

bun.lockb

1.14 KB
Binary file not shown.

package.json

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
{
2-
"name": "openapi-to-validate",
2+
"name": "openapi-static-validator",
33
"version": "0.0.0",
44
"description": "Statically compile an OpenAPI spec into a JS validation function",
55
"main": "index.js",
66
"type": "module",
77
"scripts": {
8+
"pretest": "bun run ./src/cli.ts ./tests/gitbook.json > ./tests/gitbook.validate.js",
89
"test": "bun test",
9-
"format": "prettier ./ --ignore-unknown --write"
10+
"test:update": "bun test --update-snapshots",
11+
"format": "prettier ./ --ignore-unknown --write",
12+
"build": "bun build ./src/cli.ts --compile --outfile ./dist/cli",
13+
"typecheck": "tsc --noEmit",
14+
"prepublish": "bun run build"
1015
},
1116
"author": "",
1217
"license": "ISC",
1318
"dependencies": {
1419
"ast-types": "^0.14.2",
1520
"escodegen": "^2.1.0",
16-
"hash-object": "^0.1.7",
21+
"object-hash": "^3.0.0",
1722
"path-to-regexp": "^6.2.1"
1823
},
1924
"devDependencies": {
2025
"@types/escodegen": "^0.0.9",
21-
"prettier": "^3.0.3"
26+
"@types/object-hash": "^3.0.5",
27+
"bun-types": "^1.0.6",
28+
"prettier": "^3.0.3",
29+
"typescript": "^5.2.2"
30+
},
31+
"bin": {
32+
"openapi-static-validator": "./dist/cli"
2233
}
2334
}

run.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/cli.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Compiler } from './compiler';
2+
import { readFileSync } from 'node:fs';
3+
4+
import { name } from '../package.json';
5+
6+
const inputFile = process.argv[2];
7+
8+
if (!inputFile) {
9+
console.error(`Usage: ${name} <spec>`);
10+
process.exit(1);
11+
}
12+
13+
const spec = JSON.parse(readFileSync(inputFile, 'utf-8'));
14+
15+
const compiler = new Compiler(spec);
16+
const code = compiler.compile();
17+
18+
console.log(code);

src/compileOperation.ts

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { OpenAPIParsedPath, getPathParamIndex, openapiPathToRegex } from './path
2020
export function compileOperation(
2121
compiler: Compiler,
2222
path: OpenAPIParsedPath,
23-
operation: OpenAPIOperation
23+
operation: OpenAPIOperation,
2424
) {
2525
return compiler.declareForInput(operation, (functionId) => {
2626
const requestIdentifier = builders.identifier('request');
@@ -35,30 +35,34 @@ export function compileOperation(
3535
builders.expressionStatement(
3636
builders.assignmentExpression(
3737
'=',
38-
builders.memberExpression(requestIdentifier, builders.identifier('operationId')),
38+
builders.memberExpression(
39+
requestIdentifier,
40+
builders.identifier('operationId'),
41+
),
3942
builders.literal(operation.operationId),
4043
),
4144
),
4245
);
4346
}
4447

4548
// Extract and validate path params
46-
const pathParameters = (operation.parameters ?? []).filter((parameter) => parameter.in === 'path');
49+
const pathParameters = (operation.parameters ?? []).filter(
50+
(parameter) => parameter.in === 'path',
51+
);
4752
nodes.push(
4853
builders.expressionStatement(
4954
builders.assignmentExpression(
5055
'=',
5156
builders.memberExpression(requestIdentifier, builders.identifier('params')),
5257
builders.objectExpression(
53-
pathParameters.map((parameter, index) => {
54-
const identifier = builders.identifier(`pathParam${index}`);
55-
const schemaFn = compileValueSchema(compiler, parameter.schema);
56-
const regexMatchIndex = getPathParamIndex(path, parameter.name);
57-
58-
nodes.push(
59-
builders.variableDeclaration(
60-
'const',
61-
[
58+
pathParameters
59+
.map((parameter, index) => {
60+
const identifier = builders.identifier(`pathParam${index}`);
61+
const schemaFn = compileValueSchema(compiler, parameter.schema);
62+
const regexMatchIndex = getPathParamIndex(path, parameter.name);
63+
64+
nodes.push(
65+
builders.variableDeclaration('const', [
6266
builders.variableDeclarator(
6367
identifier,
6468
builders.callExpression(schemaFn, [
@@ -74,40 +78,40 @@ export function compileOperation(
7478
contextIdentifier,
7579
]),
7680
),
77-
],
78-
)
79-
);
80-
81-
// Return an error if the parameter is invalid
82-
nodes.push(
83-
builders.ifStatement(
84-
builders.binaryExpression(
85-
'instanceof',
86-
identifier,
87-
ValidationErrorIdentifier,
88-
),
89-
builders.blockStatement([
90-
builders.returnStatement(identifier),
9181
]),
92-
),
93-
);
82+
);
9483

95-
return builders.property(
96-
'init',
97-
builders.identifier(parameter.name),
98-
identifier,
99-
);
100-
}).flat()
84+
// Return an error if the parameter is invalid
85+
nodes.push(
86+
builders.ifStatement(
87+
builders.binaryExpression(
88+
'instanceof',
89+
identifier,
90+
ValidationErrorIdentifier,
91+
),
92+
builders.blockStatement([
93+
builders.returnStatement(identifier),
94+
]),
95+
),
96+
);
97+
98+
return builders.property(
99+
'init',
100+
builders.identifier(parameter.name),
101+
identifier,
102+
);
103+
})
104+
.flat(),
101105
),
102106
),
103107
),
104108
);
105109

106110
// Validate query parameters
107-
const queryParameters = (operation.parameters ?? []).filter((parameter) => parameter.in === 'path');
108-
queryParameters.forEach((parameter) => {
109-
110-
});
111+
const queryParameters = (operation.parameters ?? []).filter(
112+
(parameter) => parameter.in === 'path',
113+
);
114+
queryParameters.forEach((parameter) => {});
111115

112116
// Validate the body against the schema
113117
if (operation.requestBody) {
@@ -116,7 +120,10 @@ export function compileOperation(
116120
builders.ifStatement(
117121
builders.binaryExpression(
118122
'===',
119-
builders.memberExpression(requestIdentifier, builders.identifier('body')),
123+
builders.memberExpression(
124+
requestIdentifier,
125+
builders.identifier('body'),
126+
),
120127
builders.identifier('undefined'),
121128
),
122129
builders.blockStatement([
@@ -136,10 +143,11 @@ export function compileOperation(
136143
builders.variableDeclarator(
137144
bodyResult,
138145
builders.callExpression(bodyFn, [
139-
builders.arrayExpression([
140-
builders.literal('body'),
141-
]),
142-
builders.memberExpression(requestIdentifier, builders.identifier('body')),
146+
builders.arrayExpression([builders.literal('body')]),
147+
builders.memberExpression(
148+
requestIdentifier,
149+
builders.identifier('body'),
150+
),
143151
]),
144152
),
145153
]),
@@ -157,7 +165,10 @@ export function compileOperation(
157165
builders.expressionStatement(
158166
builders.assignmentExpression(
159167
'=',
160-
builders.memberExpression(requestIdentifier, builders.identifier('body')),
168+
builders.memberExpression(
169+
requestIdentifier,
170+
builders.identifier('body'),
171+
),
161172
bodyResult,
162173
),
163174
),
@@ -182,13 +193,10 @@ export function compileOperation(
182193

183194
nodes.push(builders.returnStatement(requestIdentifier));
184195

185-
return builders.functionDeclaration(functionId,
186-
[
187-
requestIdentifier,
188-
pathMatchIdentifier,
189-
contextIdentifier,
190-
],
191-
builders.blockStatement(nodes)
192-
)
196+
return builders.functionDeclaration(
197+
functionId,
198+
[requestIdentifier, pathMatchIdentifier, contextIdentifier],
199+
builders.blockStatement(nodes),
200+
);
193201
});
194202
}

src/compilePath.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { OpenAPIParsedPath } from './paths';
2020
export function compilePath(
2121
compiler: Compiler,
2222
path: OpenAPIParsedPath,
23-
pathOperations: OpenAPIPath
23+
pathOperations: OpenAPIPath,
2424
) {
2525
return compiler.declareForInput(pathOperations, (functionId) => {
2626
const requestIdentifier = builders.identifier('request');
@@ -30,7 +30,7 @@ export function compilePath(
3030
const nodes: namedTypes.BlockStatement['body'] = [];
3131

3232
Object.entries(pathOperations).forEach(([method, operation]) => {
33-
const fnOperation = compileOperation(compiler,path, operation);
33+
const fnOperation = compileOperation(compiler, path, operation);
3434

3535
nodes.push(
3636
builders.ifStatement(
@@ -41,7 +41,11 @@ export function compilePath(
4141
),
4242
builders.blockStatement([
4343
builders.returnStatement(
44-
builders.callExpression(fnOperation, [requestIdentifier, pathMatchIdentifier, contextIdentifier]),
44+
builders.callExpression(fnOperation, [
45+
requestIdentifier,
46+
pathMatchIdentifier,
47+
contextIdentifier,
48+
]),
4549
),
4650
]),
4751
),
@@ -50,13 +54,10 @@ export function compilePath(
5054

5155
nodes.push(builders.returnStatement(buildValidationError('method not supported')));
5256

53-
return builders.functionDeclaration(functionId,
54-
[
55-
requestIdentifier,
56-
pathMatchIdentifier,
57-
contextIdentifier,
58-
],
59-
builders.blockStatement(nodes)
60-
)
57+
return builders.functionDeclaration(
58+
functionId,
59+
[requestIdentifier, pathMatchIdentifier, contextIdentifier],
60+
builders.blockStatement(nodes),
61+
);
6162
});
6263
}

0 commit comments

Comments
 (0)