bootpress 5.0.1 → 6.0.0

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 CHANGED
@@ -1,8 +1,11 @@
1
1
  <h1 align="center" style="margin-bottom: 0" >
2
- <img src="bootpress.svg" height=120 alt="bootpress">
2
+ <img src="https://raw.githubusercontent.com/ufukbakan/bootpress/main/bootpress.svg" height=120 alt="bootpress">
3
3
  </h1>
4
4
  <p align=center>Express but Spring Boot like</p>
5
5
 
6
+ ## Quick Start
7
+ Recommended tool: [create-bootpress-app](https://www.npmjs.com/package/create-bootpress-app)
8
+
6
9
  ## Methods
7
10
  ### **<u>RestService</u>**: Converts all methods to Express RequestHandlers
8
11
  #### Basic usage:
@@ -1,4 +1,4 @@
1
- import { HttpError } from "..";
1
+ import { HttpError } from "../types";
2
2
 
3
3
  type TypeMap = {
4
4
  "string": string,
@@ -10,7 +10,7 @@ type TypeMap = {
10
10
  }
11
11
 
12
12
  type ValidTypeKeys = keyof TypeMap;
13
- type ValOf<T extends keyof TypeMap> = TypeMap[T]
13
+ type ValOf<T extends ValidTypeKeys> = TypeMap[T]
14
14
 
15
15
  type StringEndsWithQm = `${string}?`;
16
16
 
@@ -35,4 +35,27 @@ export function asNumber(o: any): number;
35
35
  export function asInteger(o: any): number;
36
36
  export function asString(o: any): string;
37
37
  export function asSchema<T extends JsSchema>(o: any, jsSchema: T): TypedSchema<T>;
38
- export function schema<T extends JsSchema>(schema: T): T;
38
+ export function schema<T extends JsSchema>(schema: T): T;
39
+
40
+ type ExtendedTypeMap = {
41
+ "string": string,
42
+ "string[]": string[],
43
+ "boolean": boolean,
44
+ "boolean[]": boolean[],
45
+ "number": number,
46
+ "number[]": number[],
47
+ "integer": number,
48
+ "integer[]": number[],
49
+ "string?": string | null,
50
+ "string[]?": string[] | null,
51
+ "boolean?": boolean | null,
52
+ "boolean[]?": boolean[] | null,
53
+ "number?": number | null,
54
+ "number[]?": number[] | null,
55
+ "integer?": number | null,
56
+ "integer[]?": number[] | null
57
+ }
58
+
59
+ type ExtendedTypeKeys = keyof ExtendedTypeMap;
60
+ type ExtValOf<T extends ExtendedTypeKeys> = ExtendedTypeMap[T]
61
+ export function as<T extends (ExtendedTypeKeys | JsSchema | ArraySchema)>(o:any, schema: T): T extends ExtendedTypeKeys ? ExtValOf<T> : TypedSchema<T>;
package/helpers/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const { HttpError } = require("..");
1
+ const { HttpError } = require("../types");
2
2
 
3
3
  function getOrThrow(data, error) {
4
4
  if (data === null || data === undefined) {
@@ -34,6 +34,9 @@ function asBoolean(o, errorMessage = undefined, errorStatus = 400) {
34
34
  return validBooleanStrings.get(lowercased);
35
35
  } else if (typeof o === "boolean") {
36
36
  return o;
37
+ } else if (typeof o === "number"){
38
+ if(o === 1) return true;
39
+ if(o === 0) return false;
37
40
  }
38
41
  throw new HttpError(errorStatus, errorMessage);
39
42
  }
@@ -102,8 +105,8 @@ function asSchema(o, schema) {
102
105
  else if (typeof expectedType === "string") {
103
106
  if (expectedType.endsWith("[]")) {
104
107
  const elementType = expectedType.replace("[]", "");
105
- for (let j = 0; j < o[key].length; j++){
106
- if(typeof o[key][j] !== elementType){
108
+ for (let j = 0; j < o[key].length; j++) {
109
+ if (typeof o[key][j] !== elementType) {
107
110
  throw new HttpError(400, `Each element of ${key} should have been a ${elementType} but a ${typeof o[key][j]} is present (${o[key][j]})`);
108
111
  }
109
112
  }
@@ -127,6 +130,73 @@ function schema(schema) {
127
130
  return schema;
128
131
  }
129
132
 
133
+ function asArrayOf(o, elementType) {
134
+ if (Array.isArray(o)) {
135
+ for (let i = 0; i < o.length; i++) {
136
+ if(elementType === "integer"){
137
+ asInteger(o[i]);
138
+ }else if(typeof o[i] != elementType){
139
+ throw new HttpError(400, `Each element in array should have been a ${elementType} but ${o[i]} is present with type ${typeof o[i]}`);
140
+ }
141
+ }
142
+ return o;
143
+ } else {
144
+ throw new HttpError(400, `Provided object is not an array: ${JSON.stringify(o)}`)
145
+ }
146
+ }
147
+
148
+ function as(o, type) {
149
+ if (typeof type == "string") {
150
+ if (type.endsWith("[]")) {
151
+ // array check
152
+ const elementType = type.replace("[]", "");
153
+ return asArrayOf(o, elementType);
154
+ } else {
155
+ if(type.endsWith("?") && o == null){
156
+ return null;
157
+ }else if(type.endsWith("?") && o != null ){
158
+ const actualType = type.replace("?", "");
159
+ return as(o, actualType);
160
+ }
161
+ // primitive check
162
+ switch (type) {
163
+ case "string":
164
+ return asString(o);
165
+ case "number":
166
+ return asNumber(o);
167
+ case "boolean":
168
+ return asBoolean(o);
169
+ case "integer":
170
+ return asInteger(o);
171
+ default:
172
+ throw new HttpError(500, `Unsupported type ${type}`);
173
+ }
174
+ }
175
+ } else if (typeof type == "object" && type != null) {
176
+ if (Array.isArray(type)) {
177
+ if(type.length > 1){
178
+ throw new HttpError(500, `You can define only one schema for types ArrayOf<Schema>`);
179
+ }else if (type.length < 1){
180
+ throw new HttpError(500, `You must define a schema for types ArrayOf<Schema>`);
181
+ }
182
+ // array schema validation
183
+ if(!Array.isArray(o)){
184
+ throw new HttpError(400, `Provided value should have been an array. (${JSON.stringify(o)})`)
185
+ }
186
+ const providedSchema = type[0];
187
+ for(let i = 0; i < o.length; i++){
188
+ asSchema(o[i], providedSchema);
189
+ }
190
+ return o;
191
+ } else {
192
+ // schema validation
193
+ return asSchema(o, type);
194
+ }
195
+ } else {
196
+ throw new HttpError(500, `Unsupported type check ${type}`)
197
+ }
198
+ }
199
+
130
200
  module.exports = {
131
201
  getOrThrow,
132
202
  getOrElse,
@@ -135,5 +205,6 @@ module.exports = {
135
205
  asInteger,
136
206
  asString,
137
207
  asSchema,
138
- schema
208
+ schema,
209
+ as
139
210
  }
package/index.d.ts CHANGED
@@ -1,21 +1,9 @@
1
- import { Response } from "express"
2
- import { Request } from "express"
1
+ import { Response, Request } from "express"
2
+ import { ArraySchema, JsSchema, ValidTypeKeys } from "./helpers"
3
3
 
4
4
  type RequestHandler = (req: Request, res: Response) => void
5
5
  type RequsetHandlerWithArgs = (...args: any[]) => RequestHandler
6
6
 
7
- declare class HttpError extends Error {
8
- status: number
9
- message: string
10
- constructor(status: number, message: string)
11
- }
12
-
13
- declare class HttpResponse<T> {
14
- status: number
15
- data: T
16
- constructor(status: number, data: T)
17
- }
18
-
19
7
  type RestedService<T extends Record<string, any>> = { [K in keyof T]:
20
8
  T[K] extends Function
21
9
  ? (...args: Parameters<T[K]>) => RequestHandler
@@ -28,17 +16,16 @@ declare function RestMethod<T>(callback: () => T): RequestHandler;
28
16
  declare function Restify(target: any, key: string, desc: PropertyDescriptor): PropertyDescriptor;
29
17
 
30
18
  declare function PassBody(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
19
+ declare function PassBodyAs(type: ValidTypeKeys | JsSchema | ArraySchema ): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
31
20
  declare function PassRequest(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
32
21
  declare function PassAllParams(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
33
22
  declare function PassAllQueries(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
34
23
  declare function PassAllCookies(serviceFunction: RequestHandler | RequsetHandlerWithArgs): RequestHandler
35
24
  declare function PassParams(...paramNames: string[]): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
36
25
  declare function PassQueries(...queryNames: string[]): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
37
- declare function PassCookies(...cookieNames: string[]): (serviceFunction: RequestHandler |RequsetHandlerWithArgs) => RequestHandler
26
+ declare function PassCookies(...cookieNames: string[]): (serviceFunction: RequestHandler | RequsetHandlerWithArgs) => RequestHandler
38
27
 
39
28
  export {
40
- HttpError,
41
- HttpResponse,
42
29
  RestService,
43
30
  RestMethod,
44
31
  Restify,
@@ -49,5 +36,6 @@ export {
49
36
  PassCookies,
50
37
  PassAllCookies,
51
38
  PassBody,
39
+ PassBodyAs,
52
40
  PassRequest
53
41
  }
package/index.js CHANGED
@@ -1,18 +1,5 @@
1
- class HttpError extends Error {
2
- constructor(status, message) {
3
- super(message);
4
- this.stack += "\n" + message;
5
- this.message = message;
6
- this.status = status;
7
- }
8
- }
9
-
10
- class HttpResponse {
11
- constructor(status, data) {
12
- this.status = status;
13
- this.data = data;
14
- }
15
- }
1
+ const { as } = require("./helpers");
2
+ const { HttpError } = require("./types");
16
3
 
17
4
  const protectedProperties = [
18
5
  "toString",
@@ -171,6 +158,19 @@ function PassBody(actualHandler) {
171
158
  }
172
159
  }
173
160
 
161
+ function PassBodyAs(type) {
162
+ return (actualHandler) => {
163
+ return (...args) => {
164
+ if (isRequstHandlerArgs(args)) {
165
+ const req = args.at(-3); const res = args.at(-2);
166
+ return actualHandler(as(req.body, type))(req, res);
167
+ } else {
168
+ return (req, res) => actualHandler(...args, as(req.body, type))(req, res);
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
174
  function PassRequest(actualHandler) {
175
175
  return (...args) => {
176
176
  if (isRequstHandlerArgs(args)) {
@@ -208,8 +208,6 @@ function PassCookies(...cookieNames) {
208
208
  }
209
209
 
210
210
  module.exports = {
211
- HttpError,
212
- HttpResponse,
213
211
  RestService,
214
212
  RestMethod,
215
213
  Restify,
@@ -220,5 +218,6 @@ module.exports = {
220
218
  PassAllCookies,
221
219
  PassCookies,
222
220
  PassBody,
221
+ PassBodyAs,
223
222
  PassRequest
224
223
  }
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "bootpress",
3
- "version": "5.0.1",
3
+ "version": "6.0.0",
4
4
  "description": "REST service methods for express",
5
5
  "main": "index.js",
6
- "scripts": {},
7
6
  "repository": {
8
7
  "type": "git",
9
8
  "url": "git+https://github.com/ufukbakan/bootpress.git"
@@ -28,7 +27,7 @@
28
27
  "express": "^4.18.2"
29
28
  },
30
29
  "devDependencies": {
31
- "@types/body-parser": "^1.19.2",
32
- "@types/express": "^4.17.17"
30
+ "@types/express": "^4.17.17",
31
+ "typescript": "^4.9.5"
33
32
  }
34
33
  }
package/types/index.js ADDED
@@ -0,0 +1,20 @@
1
+ class HttpError extends Error {
2
+ constructor(status, message) {
3
+ super(message);
4
+ this.stack += "\n" + message;
5
+ this.message = message;
6
+ this.status = status;
7
+ }
8
+ }
9
+
10
+ class HttpResponse {
11
+ constructor(status, data) {
12
+ this.status = status;
13
+ this.data = data;
14
+ }
15
+ }
16
+
17
+ module.exports = {
18
+ HttpError,
19
+ HttpResponse
20
+ }
package/types/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ declare class HttpError extends Error {
2
+ status: number
3
+ message: string
4
+ constructor(status: number, message: string)
5
+ }
6
+
7
+ declare class HttpResponse<T> {
8
+ status: number
9
+ data: T
10
+ constructor(status: number, data: T)
11
+ }
12
+
13
+ export {
14
+ HttpError,
15
+ HttpResponse
16
+ }