@effect-app/infra 0.71.2 → 0.72.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.
- package/CHANGELOG.md +12 -0
- package/_cjs/api/express/makeJsonSchema.cjs +93 -53
- package/_cjs/api/express/makeJsonSchema.cjs.map +1 -1
- package/_cjs/api/express/makeJsonSchema.test.cjs +27 -4
- package/_cjs/api/express/makeJsonSchema.test.cjs.map +1 -1
- package/_src/api/express/makeJsonSchema.test.ts +49 -8
- package/_src/api/express/makeJsonSchema.ts +102 -46
- package/dist/api/express/makeJsonSchema.d.ts +2 -3
- package/dist/api/express/makeJsonSchema.d.ts.map +1 -1
- package/dist/api/express/makeJsonSchema.js +87 -41
- package/dist/api/express/makeOpenApiSpecs.d.ts +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @effect-app/infra
|
|
2
2
|
|
|
3
|
+
## 0.72.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 13942e1b: disable shadowing bekause it is broken as \*\*\*\*
|
|
8
|
+
|
|
9
|
+
## 0.72.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- b6af4d2f: enhance shadowing paths check
|
|
14
|
+
|
|
3
15
|
## 0.71.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.checkPaths = checkPaths;
|
|
7
7
|
exports.makeJsonSchema = makeJsonSchema;
|
|
8
8
|
var tsplus_module_1 = _interopRequireWildcard(require("@effect/io/Effect"));
|
|
9
9
|
var tsplus_module_2 = _interopRequireWildcard(require("@effect/data/Chunk"));
|
|
@@ -15,68 +15,108 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
15
15
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
16
16
|
|
|
17
17
|
const rx = /:(\w+)/g;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
18
|
+
class PathsTree {
|
|
19
|
+
constructor(path) {
|
|
20
|
+
this.methods = [];
|
|
21
|
+
this.params = {};
|
|
22
|
+
this.subpaths = {};
|
|
23
|
+
this.path = path;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// interface Match {
|
|
27
|
+
// _tag: "resource" | "param"
|
|
28
|
+
// value: string
|
|
29
|
+
// }
|
|
30
|
+
// function checkShadowing(
|
|
31
|
+
// pathNavigator: PathsTree,
|
|
32
|
+
// match: Match
|
|
33
|
+
// ) {
|
|
34
|
+
// return Effect.gen(function*($) {
|
|
35
|
+
// switch (match._tag) {
|
|
36
|
+
// case "resource": {
|
|
37
|
+
// // check shadowing: if 'a/:param' comes before 'a/b', then 'a/b' is shadowed
|
|
38
|
+
// if (pathNavigator.params[1]) {
|
|
39
|
+
// return yield* $(Effect.fail(
|
|
40
|
+
// new InvalidStateError(
|
|
41
|
+
// `Path ${pathNavigator.path}${match.value}/ is shadowed by ${pathNavigator.params[1].path}`
|
|
42
|
+
// )
|
|
43
|
+
// ))
|
|
44
|
+
// }
|
|
45
|
+
// break
|
|
46
|
+
// }
|
|
47
|
+
// case "param": {
|
|
48
|
+
// // check shadowing: if 'a/b' comes before 'a/:param', then 'a/"param' is partially shadowed
|
|
49
|
+
// const subpaths = Object.getOwnPropertyNames(pathNavigator.subpaths)
|
|
50
|
+
// if (subpaths.length > 0) {
|
|
51
|
+
// yield* $(subpaths.forEachEffect((s) =>
|
|
52
|
+
// Effect.logInfo(
|
|
53
|
+
// `Path ${pathNavigator.path}:${match.value}/ is partially shadowed by ${pathNavigator.subpaths[s]!.path}`
|
|
54
|
+
// )
|
|
55
|
+
// ))
|
|
56
|
+
// }
|
|
57
|
+
// break
|
|
58
|
+
// }
|
|
59
|
+
// }
|
|
60
|
+
// })
|
|
61
|
+
// }
|
|
62
|
+
function checkPaths(paths) {
|
|
63
|
+
return tsplus_module_1.gen(function* ($) {
|
|
64
|
+
const pathMethods = new PathsTree("/");
|
|
65
|
+
const regex = /(?:^|\/)([^/:\n]+)|:(\w+)/g;
|
|
66
|
+
for (const path of paths) {
|
|
67
|
+
const matches = [...path.path.matchAll(regex)].map(match => match[1] ? {
|
|
68
|
+
_tag: "resource",
|
|
69
|
+
value: match[1]
|
|
70
|
+
} : {
|
|
71
|
+
_tag: "param",
|
|
72
|
+
value: match[2]
|
|
73
|
+
});
|
|
74
|
+
let pathNavigator = pathMethods;
|
|
75
|
+
for (let i = 0; i < matches.length;) {
|
|
76
|
+
const match = matches[i];
|
|
77
|
+
// yield* $(checkShadowing(pathNavigator, match))
|
|
78
|
+
switch (match._tag) {
|
|
79
|
+
case "resource":
|
|
80
|
+
{
|
|
81
|
+
if (!(match.value in pathNavigator.subpaths)) {
|
|
82
|
+
pathNavigator.subpaths[match.value] = new PathsTree(`${pathNavigator.path}${match.value}/`);
|
|
83
|
+
}
|
|
84
|
+
pathNavigator = pathNavigator.subpaths[match.value];
|
|
53
85
|
i++;
|
|
86
|
+
break;
|
|
54
87
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
88
|
+
case "param":
|
|
89
|
+
{
|
|
90
|
+
const paramsNames = [match.value];
|
|
91
|
+
let numberOfParams = 1;
|
|
92
|
+
while (i < matches.length && matches[i + 1]?._tag === "param") {
|
|
93
|
+
numberOfParams++;
|
|
94
|
+
i++;
|
|
95
|
+
paramsNames.push(matches[i].value);
|
|
96
|
+
}
|
|
97
|
+
if (!(numberOfParams in pathNavigator.params)) {
|
|
98
|
+
pathNavigator.params[numberOfParams] = new PathsTree(`${pathNavigator.path}:${paramsNames.join("/:")}/`);
|
|
99
|
+
}
|
|
100
|
+
pathNavigator = pathNavigator.params[numberOfParams];
|
|
101
|
+
i++;
|
|
102
|
+
break;
|
|
60
103
|
}
|
|
61
|
-
|
|
62
|
-
i++;
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
104
|
+
}
|
|
65
105
|
}
|
|
106
|
+
if (pathNavigator.methods.includes(path.method)) {
|
|
107
|
+
// throw duplicate path-method error
|
|
108
|
+
return yield* $(tsplus_module_1.fail(new _errors.InvalidStateError(`Duplicate method ${path.method} for path ${path.path}`)));
|
|
109
|
+
}
|
|
110
|
+
pathNavigator.methods.push(path.method);
|
|
66
111
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return tsplus_module_1.fail(new _errors.InvalidStateError(`Duplicate method ${path.method} for path ${path.path}`));
|
|
70
|
-
}
|
|
71
|
-
pathNavigator[methods].push(path.method);
|
|
72
|
-
}
|
|
73
|
-
return tsplus_module_1.succeed(paths);
|
|
112
|
+
return paths;
|
|
113
|
+
});
|
|
74
114
|
}
|
|
75
115
|
/**
|
|
76
116
|
* Work in progress JSONSchema generator.
|
|
77
117
|
*/
|
|
78
118
|
function makeJsonSchema(r) {
|
|
79
|
-
return tsplus_module_1.map(tsplus_module_1.flatMap(tsplus_module_3.ext_forEach(tsplus_module_2.fromIterable(r), RS.makeFromSchema),
|
|
119
|
+
return tsplus_module_1.map(tsplus_module_1.flatMap(tsplus_module_3.ext_forEach(tsplus_module_2.fromIterable(r), RS.makeFromSchema), checkPaths), e => {
|
|
80
120
|
const map = ({
|
|
81
121
|
method,
|
|
82
122
|
path,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeJsonSchema.cjs","names":["_errors","require","RS","_interopRequireWildcard","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","rx","
|
|
1
|
+
{"version":3,"file":"makeJsonSchema.cjs","names":["_errors","require","RS","_interopRequireWildcard","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","rx","PathsTree","constructor","path","methods","params","subpaths","checkPaths","paths","tsplus_module_1","gen","$","pathMethods","regex","matches","matchAll","map","match","_tag","value","pathNavigator","i","length","paramsNames","numberOfParams","push","join","includes","method","fail","InvalidStateError","makeJsonSchema","r","flatMap","tsplus_module_3","ext_forEach","tsplus_module_2","fromIterable","makeFromSchema","e","responses","rest","reduce","prev","cur","statusCode","type","split","replace","_a","b","Response"],"sources":["../../../_src/api/express/makeJsonSchema.ts"],"sourcesContent":[null],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var tsplus_module_1 = _interopRequireWildcard(require("@effect/io/Effect"));
|
|
4
|
+
var tsplus_module_2 = _interopRequireWildcard(require("@effect/data/Either"));
|
|
4
5
|
var _errors = require("../../errors.cjs");
|
|
5
6
|
var _makeJsonSchema = require("./makeJsonSchema.cjs");
|
|
6
7
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
@@ -13,15 +14,37 @@ const equalPaths = ["/securities/:idt/search/:id2", "/securities/:id/search/:id2
|
|
|
13
14
|
path,
|
|
14
15
|
method: "get"
|
|
15
16
|
}));
|
|
16
|
-
const differentPaths = ["/securities/:id/search/", "/securities/search/:id2", "/securities/:id/:id2/search/:id3"].map(path => ({
|
|
17
|
+
const differentPaths = ["/securities/search/:id2", "/securities/:id/search/", "/securities/:id/search/:id2", "/securities/:id/:id2/search/:id3"].map(path => ({
|
|
17
18
|
path,
|
|
18
19
|
method: "get"
|
|
19
20
|
})).concat(["/securities/:idt/search/:id2"].map(path => ({
|
|
20
21
|
path,
|
|
21
22
|
method: "post"
|
|
22
23
|
})));
|
|
23
|
-
test("works", () => {
|
|
24
|
-
expect((0, _makeJsonSchema.
|
|
25
|
-
|
|
24
|
+
test("works", async () => {
|
|
25
|
+
expect(await tsplus_module_1.runPromise((0, _makeJsonSchema.checkPaths)(differentPaths))).toStrictEqual(differentPaths);
|
|
26
|
+
for (const p of equalPaths) {
|
|
27
|
+
expect(await tsplus_module_1.runPromiseEither((0, _makeJsonSchema.checkPaths)([path, p]))).toStrictEqual(tsplus_module_2.left(new _errors.InvalidStateError(`Duplicate method ${p.method} for path ${p.path}`)));
|
|
28
|
+
}
|
|
29
|
+
// should it error out? I think not
|
|
30
|
+
// expect(await checkPaths(["a/:p1/c/:p2", "a/b"].map((path) => ({ path, method: "get" }))).runPromiseEither)
|
|
31
|
+
// .toStrictEqual(
|
|
32
|
+
// Either.left(new InvalidStateError(`Path /a/b/ is shadowed by /a/:p1/`))
|
|
33
|
+
// )
|
|
34
|
+
// should not error out
|
|
35
|
+
// expect(await checkPaths([{ path: "a/:p1/c/:p2", method: "post" }, { path: "a/b", method: "get" }]).runPromiseEither)
|
|
36
|
+
// .toStrictEqual(
|
|
37
|
+
// Either.left(new InvalidStateError(`Path /a/b/ is shadowed by /a/:p1/`))
|
|
38
|
+
// )
|
|
39
|
+
// should not error out
|
|
40
|
+
// expect(await checkPaths([{ path: "a/:param/c/d", method: "get" }, { path: "a/b/c/e", method: "get" }]).runPromiseEither)
|
|
41
|
+
// .toStrictEqual(
|
|
42
|
+
// Either.left(new InvalidStateError(`Path /a/b/ is shadowed by /a/:p1/`))
|
|
43
|
+
// )
|
|
44
|
+
// it should error out
|
|
45
|
+
// expect(await checkPaths(["a/:p1/c/:p2", "a/:p111/c/d"].map((path) => ({ path, method: "get" }))).runPromiseEither)
|
|
46
|
+
// .toStrictEqual(
|
|
47
|
+
// Either.left(new InvalidStateError(`Path /a/:p1/c/d/ is shadowed by /a/:p1/c/:p2/`))
|
|
48
|
+
// )
|
|
26
49
|
});
|
|
27
50
|
//# sourceMappingURL=makeJsonSchema.test.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeJsonSchema.test.cjs","names":["_errors","require","_makeJsonSchema","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","_interopRequireWildcard","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","path","method","equalPaths","map","differentPaths","concat","test","expect","
|
|
1
|
+
{"version":3,"file":"makeJsonSchema.test.cjs","names":["_errors","require","_makeJsonSchema","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","_interopRequireWildcard","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","path","method","equalPaths","map","differentPaths","concat","test","expect","tsplus_module_1","runPromise","checkPaths","toStrictEqual","p","runPromiseEither","tsplus_module_2","left","InvalidStateError"],"sources":["../../../_src/api/express/makeJsonSchema.test.ts"],"sourcesContent":[null],"mappings":";;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAAgD,SAAAE,yBAAAC,WAAA,eAAAC,OAAA,kCAAAC,iBAAA,OAAAD,OAAA,QAAAE,gBAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,WAAA,WAAAA,WAAA,GAAAG,gBAAA,GAAAD,iBAAA,KAAAF,WAAA;AAAA,SAAAI,wBAAAC,GAAA,EAAAL,WAAA,SAAAA,WAAA,IAAAK,GAAA,IAAAA,GAAA,CAAAC,UAAA,WAAAD,GAAA,QAAAA,GAAA,oBAAAA,GAAA,wBAAAA,GAAA,4BAAAE,OAAA,EAAAF,GAAA,UAAAG,KAAA,GAAAT,wBAAA,CAAAC,WAAA,OAAAQ,KAAA,IAAAA,KAAA,CAAAC,GAAA,CAAAJ,GAAA,YAAAG,KAAA,CAAAE,GAAA,CAAAL,GAAA,SAAAM,MAAA,WAAAC,qBAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,GAAA,IAAAX,GAAA,QAAAW,GAAA,kBAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAd,GAAA,EAAAW,GAAA,SAAAI,IAAA,GAAAR,qBAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAV,GAAA,EAAAW,GAAA,cAAAI,IAAA,KAAAA,IAAA,CAAAV,GAAA,IAAAU,IAAA,CAAAC,GAAA,KAAAR,MAAA,CAAAC,cAAA,CAAAH,MAAA,EAAAK,GAAA,EAAAI,IAAA,YAAAT,MAAA,CAAAK,GAAA,IAAAX,GAAA,CAAAW,GAAA,SAAAL,MAAA,CAAAJ,OAAA,GAAAF,GAAA,MAAAG,KAAA,IAAAA,KAAA,CAAAa,GAAA,CAAAhB,GAAA,EAAAM,MAAA,YAAAA,MAAA;AAEhD,MAAMW,IAAI,GAAG;EAAEA,IAAI,EAAE,6BAA6B;EAAEC,MAAM,EAAE;AAAK,CAAE;AAEnE,MAAMC,UAAU,GAAG,CACjB,8BAA8B,EAC9B,8BAA8B,EAC9B,+BAA+B,CAChC,CACEC,GAAG,CAAEH,IAAI,KAAM;EAAEA,IAAI;EAAEC,MAAM,EAAE;AAAK,CAAE,CAAC,CAAC;AAE3C,MAAMG,cAAc,GAGd,CACJ,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,EAC7B,kCAAkC,CACnC,CACED,GAAG,CAAEH,IAAI,KAAM;EAAEA,IAAI;EAAEC,MAAM,EAAE;AAAK,CAAE,CAAC,CAAC,CACxCI,MAAM,CAAC,CACN,8BAA8B,CAC/B,CACEF,GAAG,CAAEH,IAAI,KAAM;EAAEA,IAAI;EAAEC,MAAM,EAAE;AAAM,CAAE,CAAC,CAAC,CAAC;AAE/CK,IAAI,CAAC,OAAO,EAAE,YAAW;EACvBC,MAAM,CAAC,MAAAC,eAAA,CAAAC,UAAA,CAAO,IAAAC,0BAAU,EAACN,cAAc,CAAE,CAAW,CAAC,CAACO,aAAa,CAACP,cAAc,CAAC;EAEnF,KAAK,MAAMQ,CAAC,IAAIV,UAAU,EAAE;IAC1BK,MAAM,CAAC,MAAAC,eAAA,CAAAK,gBAAA,CAAM,IAAAH,0BAAU,EAAC,CAACV,IAAI,EAAEY,CAAC,CAAC,CAAC,CAAiB,CAAC,CAACD,aAAa,CAChEG,eAAA,CAAAC,IAAA,CAAY,IAAIC,yBAAiB,CAAC,oBAAoBJ,CAAC,CAACX,MAAM,aAAaW,CAAC,CAACZ,IAAI,EAAE,CAAC,CAAC,CACtF;;EAGH;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;AACF,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InvalidStateError } from "../../errors.js"
|
|
2
|
-
import {
|
|
2
|
+
import { checkPaths } from "./makeJsonSchema.js"
|
|
3
3
|
|
|
4
4
|
const path = { path: "/securities/:id/search/:id2", method: "get" }
|
|
5
5
|
|
|
@@ -14,8 +14,9 @@ const differentPaths: {
|
|
|
14
14
|
path: string
|
|
15
15
|
method: string
|
|
16
16
|
}[] = [
|
|
17
|
-
"/securities/:id/search/",
|
|
18
17
|
"/securities/search/:id2",
|
|
18
|
+
"/securities/:id/search/",
|
|
19
|
+
"/securities/:id/search/:id2",
|
|
19
20
|
"/securities/:id/:id2/search/:id3"
|
|
20
21
|
]
|
|
21
22
|
.map((path) => ({ path, method: "get" }))
|
|
@@ -24,12 +25,52 @@ const differentPaths: {
|
|
|
24
25
|
]
|
|
25
26
|
.map((path) => ({ path, method: "post" })))
|
|
26
27
|
|
|
27
|
-
test("works", () => {
|
|
28
|
-
expect(
|
|
28
|
+
test("works", async () => {
|
|
29
|
+
expect(await (checkPaths(differentPaths)).runPromise).toStrictEqual(differentPaths)
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
expect(
|
|
32
|
-
|
|
31
|
+
for (const p of equalPaths) {
|
|
32
|
+
expect(await checkPaths([path, p]).runPromiseEither).toStrictEqual(
|
|
33
|
+
Either.left(new InvalidStateError(`Duplicate method ${p.method} for path ${p.path}`))
|
|
33
34
|
)
|
|
34
|
-
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// should it error out? I think not
|
|
38
|
+
// expect(await checkPaths(["a/:p1/c/:p2", "a/b"].map((path) => ({ path, method: "get" }))).runPromiseEither)
|
|
39
|
+
// .toStrictEqual(
|
|
40
|
+
// Either.left(new InvalidStateError(`Path /a/b/ is shadowed by /a/:p1/`))
|
|
41
|
+
// )
|
|
42
|
+
|
|
43
|
+
// should not error out
|
|
44
|
+
// expect(await checkPaths([{ path: "a/:p1/c/:p2", method: "post" }, { path: "a/b", method: "get" }]).runPromiseEither)
|
|
45
|
+
// .toStrictEqual(
|
|
46
|
+
// Either.left(new InvalidStateError(`Path /a/b/ is shadowed by /a/:p1/`))
|
|
47
|
+
// )
|
|
48
|
+
|
|
49
|
+
// should not error out
|
|
50
|
+
// expect(await checkPaths([{ path: "a/:param/c/d", method: "get" }, { path: "a/b/c/e", method: "get" }]).runPromiseEither)
|
|
51
|
+
// .toStrictEqual(
|
|
52
|
+
// Either.left(new InvalidStateError(`Path /a/b/ is shadowed by /a/:p1/`))
|
|
53
|
+
// )
|
|
54
|
+
|
|
55
|
+
// it should error out
|
|
56
|
+
// expect(await checkPaths(["a/:p1/c/:p2", "a/:p111/c/d"].map((path) => ({ path, method: "get" }))).runPromiseEither)
|
|
57
|
+
// .toStrictEqual(
|
|
58
|
+
// Either.left(new InvalidStateError(`Path /a/:p1/c/d/ is shadowed by /a/:p1/c/:p2/`))
|
|
59
|
+
// )
|
|
35
60
|
})
|
|
61
|
+
|
|
62
|
+
// it should log
|
|
63
|
+
// test("log shadowing", async () => {
|
|
64
|
+
// const arr: string[] = []
|
|
65
|
+
// const paths = ["a/b", "a/:p"].map((path) => ({ path, method: "get" }))
|
|
66
|
+
|
|
67
|
+
// const CustomLogger = Logger.make<string, void>((_, __, message) => {
|
|
68
|
+
// arr.push(message)
|
|
69
|
+
// })
|
|
70
|
+
|
|
71
|
+
// await checkPaths(paths)
|
|
72
|
+
// .provideLayer(Logger.replace(Logger.defaultLogger, CustomLogger))
|
|
73
|
+
// .runPromise
|
|
74
|
+
|
|
75
|
+
// expect(arr).toStrictEqual([`Path /a/:p/ is partially shadowed by /a/b/`])
|
|
76
|
+
// })
|
|
@@ -9,62 +9,118 @@ const rx = /:(\w+)/g
|
|
|
9
9
|
|
|
10
10
|
type _A<C> = C extends ReadonlyArray<infer A> ? A : never
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
class PathsTree {
|
|
13
|
+
public readonly methods: string[]
|
|
14
|
+
public readonly params: { [key: number]: PathsTree | undefined }
|
|
15
|
+
public readonly subpaths: { [key: string]: PathsTree | undefined }
|
|
16
|
+
public readonly path: string
|
|
17
|
+
|
|
18
|
+
constructor(path: string) {
|
|
19
|
+
this.methods = []
|
|
20
|
+
this.params = {}
|
|
21
|
+
this.subpaths = {}
|
|
22
|
+
this.path = path
|
|
19
23
|
}
|
|
20
|
-
|
|
21
|
-
const regex = /(?:^|\/)([^/:\n]+)|:(\w+)/g
|
|
22
|
-
|
|
23
|
-
for (const path of paths) {
|
|
24
|
-
const matches = [...path.path.matchAll(regex)]
|
|
25
|
-
.map((match) =>
|
|
26
|
-
match[1]
|
|
27
|
-
? { _tag: "resource", value: match[1] } as const
|
|
28
|
-
: { _tag: "param", value: match[2]! } as const
|
|
29
|
-
)
|
|
24
|
+
}
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
26
|
+
// interface Match {
|
|
27
|
+
// _tag: "resource" | "param"
|
|
28
|
+
// value: string
|
|
29
|
+
// }
|
|
30
|
+
|
|
31
|
+
// function checkShadowing(
|
|
32
|
+
// pathNavigator: PathsTree,
|
|
33
|
+
// match: Match
|
|
34
|
+
// ) {
|
|
35
|
+
// return Effect.gen(function*($) {
|
|
36
|
+
// switch (match._tag) {
|
|
37
|
+
// case "resource": {
|
|
38
|
+
// // check shadowing: if 'a/:param' comes before 'a/b', then 'a/b' is shadowed
|
|
39
|
+
// if (pathNavigator.params[1]) {
|
|
40
|
+
// return yield* $(Effect.fail(
|
|
41
|
+
// new InvalidStateError(
|
|
42
|
+
// `Path ${pathNavigator.path}${match.value}/ is shadowed by ${pathNavigator.params[1].path}`
|
|
43
|
+
// )
|
|
44
|
+
// ))
|
|
45
|
+
// }
|
|
46
|
+
// break
|
|
47
|
+
// }
|
|
48
|
+
// case "param": {
|
|
49
|
+
// // check shadowing: if 'a/b' comes before 'a/:param', then 'a/"param' is partially shadowed
|
|
50
|
+
// const subpaths = Object.getOwnPropertyNames(pathNavigator.subpaths)
|
|
51
|
+
// if (subpaths.length > 0) {
|
|
52
|
+
// yield* $(subpaths.forEachEffect((s) =>
|
|
53
|
+
// Effect.logInfo(
|
|
54
|
+
// `Path ${pathNavigator.path}:${match.value}/ is partially shadowed by ${pathNavigator.subpaths[s]!.path}`
|
|
55
|
+
// )
|
|
56
|
+
// ))
|
|
57
|
+
// }
|
|
58
|
+
// break
|
|
59
|
+
// }
|
|
60
|
+
// }
|
|
61
|
+
// })
|
|
62
|
+
// }
|
|
63
|
+
|
|
64
|
+
export function checkPaths<T extends { path: string; method: string }>(
|
|
65
|
+
paths: readonly T[]
|
|
66
|
+
) {
|
|
67
|
+
return Effect.gen(function*($) {
|
|
68
|
+
const pathMethods: PathsTree = new PathsTree("/")
|
|
69
|
+
const regex = /(?:^|\/)([^/:\n]+)|:(\w+)/g
|
|
70
|
+
for (const path of paths) {
|
|
71
|
+
const matches = [...path.path.matchAll(regex)]
|
|
72
|
+
.map((match) =>
|
|
73
|
+
match[1]
|
|
74
|
+
? { _tag: "resource", value: match[1] } as const
|
|
75
|
+
: { _tag: "param", value: match[2]! } as const
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
let pathNavigator = pathMethods
|
|
79
|
+
for (let i = 0; i < matches.length;) {
|
|
80
|
+
const match = matches[i]!
|
|
81
|
+
|
|
82
|
+
// yield* $(checkShadowing(pathNavigator, match))
|
|
83
|
+
|
|
84
|
+
switch (match._tag) {
|
|
85
|
+
case "resource": {
|
|
86
|
+
if (!(match.value in pathNavigator.subpaths)) {
|
|
87
|
+
pathNavigator.subpaths[match.value] = new PathsTree(`${pathNavigator.path}${match.value}/`)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
pathNavigator = pathNavigator.subpaths[match.value]!
|
|
47
91
|
i++
|
|
92
|
+
break
|
|
48
93
|
}
|
|
94
|
+
case "param": {
|
|
95
|
+
const paramsNames = [match.value]
|
|
96
|
+
let numberOfParams = 1
|
|
97
|
+
while (i < matches.length && matches[i + 1]?._tag === "param") {
|
|
98
|
+
numberOfParams++
|
|
99
|
+
i++
|
|
100
|
+
paramsNames.push(matches[i]!.value)
|
|
101
|
+
}
|
|
49
102
|
|
|
50
|
-
|
|
51
|
-
|
|
103
|
+
if (!(numberOfParams in pathNavigator.params)) {
|
|
104
|
+
pathNavigator.params[numberOfParams] = new PathsTree(
|
|
105
|
+
`${pathNavigator.path}:${paramsNames.join("/:")}/`
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
pathNavigator = pathNavigator.params[numberOfParams]!
|
|
109
|
+
i++
|
|
110
|
+
break
|
|
52
111
|
}
|
|
53
|
-
pathNavigator = (pathNavigator)[numberOfParams]!
|
|
54
|
-
i++
|
|
55
|
-
break
|
|
56
112
|
}
|
|
57
113
|
}
|
|
58
|
-
}
|
|
59
114
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
115
|
+
if (pathNavigator.methods.includes(path.method)) {
|
|
116
|
+
// throw duplicate path-method error
|
|
117
|
+
return yield* $(Effect.fail(new InvalidStateError(`Duplicate method ${path.method} for path ${path.path}`)))
|
|
118
|
+
}
|
|
119
|
+
pathNavigator.methods.push(path.method)
|
|
63
120
|
}
|
|
64
|
-
pathNavigator[methods].push(path.method)
|
|
65
|
-
}
|
|
66
121
|
|
|
67
|
-
|
|
122
|
+
return paths
|
|
123
|
+
})
|
|
68
124
|
}
|
|
69
125
|
|
|
70
126
|
/**
|
|
@@ -74,7 +130,7 @@ export function makeJsonSchema(r: Iterable<RS.RouteDescriptorAny>) {
|
|
|
74
130
|
return Chunk
|
|
75
131
|
.fromIterable(r)
|
|
76
132
|
.forEachEffect(RS.makeFromSchema)
|
|
77
|
-
.flatMap(
|
|
133
|
+
.flatMap(checkPaths)
|
|
78
134
|
.map((e) => {
|
|
79
135
|
const map = ({ method, path, responses, ...rest }: _A<typeof e>) => ({
|
|
80
136
|
[method]: {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { Effect } from "@effect/io/Effect";
|
|
2
1
|
import { InvalidStateError } from "../../errors.js";
|
|
3
2
|
import * as RS from "./schema/routing.js";
|
|
4
3
|
type Methods = "GET" | "PUT" | "POST" | "PATCH" | "DELETE";
|
|
5
|
-
export declare function
|
|
4
|
+
export declare function checkPaths<T extends {
|
|
6
5
|
path: string;
|
|
7
6
|
method: string;
|
|
8
|
-
}>(paths: readonly T[]): Effect<never, InvalidStateError, readonly T[]>;
|
|
7
|
+
}>(paths: readonly T[]): import("@effect/io/Effect").Effect<never, InvalidStateError, readonly T[]>;
|
|
9
8
|
/**
|
|
10
9
|
* Work in progress JSONSchema generator.
|
|
11
10
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeJsonSchema.d.ts","sourceRoot":"","sources":["../../../_src/api/express/makeJsonSchema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"makeJsonSchema.d.ts","sourceRoot":"","sources":["../../../_src/api/express/makeJsonSchema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAEzC,KAAK,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AA0D1D,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACnE,KAAK,EAAE,SAAS,CAAC,EAAE,8EA2DpB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,kBAAkB,CAAC;;;;;;;;;;;;;;;;;;;;;KA8BhE"}
|
|
@@ -5,57 +5,103 @@ import * as tsplus_module_3 from "@effect-app/core/_ext/Iterable";
|
|
|
5
5
|
import { InvalidStateError } from "../../errors.js";
|
|
6
6
|
import * as RS from "./schema/routing.js";
|
|
7
7
|
const rx = /:(\w+)/g;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
8
|
+
class PathsTree {
|
|
9
|
+
constructor(path) {
|
|
10
|
+
this.methods = [];
|
|
11
|
+
this.params = {};
|
|
12
|
+
this.subpaths = {};
|
|
13
|
+
this.path = path;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// interface Match {
|
|
17
|
+
// _tag: "resource" | "param"
|
|
18
|
+
// value: string
|
|
19
|
+
// }
|
|
20
|
+
// function checkShadowing(
|
|
21
|
+
// pathNavigator: PathsTree,
|
|
22
|
+
// match: Match
|
|
23
|
+
// ) {
|
|
24
|
+
// return Effect.gen(function*($) {
|
|
25
|
+
// switch (match._tag) {
|
|
26
|
+
// case "resource": {
|
|
27
|
+
// // check shadowing: if 'a/:param' comes before 'a/b', then 'a/b' is shadowed
|
|
28
|
+
// if (pathNavigator.params[1]) {
|
|
29
|
+
// return yield* $(Effect.fail(
|
|
30
|
+
// new InvalidStateError(
|
|
31
|
+
// `Path ${pathNavigator.path}${match.value}/ is shadowed by ${pathNavigator.params[1].path}`
|
|
32
|
+
// )
|
|
33
|
+
// ))
|
|
34
|
+
// }
|
|
35
|
+
// break
|
|
36
|
+
// }
|
|
37
|
+
// case "param": {
|
|
38
|
+
// // check shadowing: if 'a/b' comes before 'a/:param', then 'a/"param' is partially shadowed
|
|
39
|
+
// const subpaths = Object.getOwnPropertyNames(pathNavigator.subpaths)
|
|
40
|
+
// if (subpaths.length > 0) {
|
|
41
|
+
// yield* $(subpaths.forEachEffect((s) =>
|
|
42
|
+
// Effect.logInfo(
|
|
43
|
+
// `Path ${pathNavigator.path}:${match.value}/ is partially shadowed by ${pathNavigator.subpaths[s]!.path}`
|
|
44
|
+
// )
|
|
45
|
+
// ))
|
|
46
|
+
// }
|
|
47
|
+
// break
|
|
48
|
+
// }
|
|
49
|
+
// }
|
|
50
|
+
// })
|
|
51
|
+
// }
|
|
52
|
+
export function checkPaths(paths) {
|
|
53
|
+
return tsplus_module_1.gen(function* ($) {
|
|
54
|
+
const pathMethods = new PathsTree("/");
|
|
55
|
+
const regex = /(?:^|\/)([^/:\n]+)|:(\w+)/g;
|
|
56
|
+
for (const path of paths) {
|
|
57
|
+
const matches = [...path.path.matchAll(regex)]
|
|
58
|
+
.map((match) => match[1]
|
|
59
|
+
? { _tag: "resource", value: match[1] }
|
|
60
|
+
: { _tag: "param", value: match[2] });
|
|
61
|
+
let pathNavigator = pathMethods;
|
|
62
|
+
for (let i = 0; i < matches.length;) {
|
|
63
|
+
const match = matches[i];
|
|
64
|
+
// yield* $(checkShadowing(pathNavigator, match))
|
|
65
|
+
switch (match._tag) {
|
|
66
|
+
case "resource": {
|
|
67
|
+
if (!(match.value in pathNavigator.subpaths)) {
|
|
68
|
+
pathNavigator.subpaths[match.value] = new PathsTree(`${pathNavigator.path}${match.value}/`);
|
|
69
|
+
}
|
|
70
|
+
pathNavigator = pathNavigator.subpaths[match.value];
|
|
34
71
|
i++;
|
|
72
|
+
break;
|
|
35
73
|
}
|
|
36
|
-
|
|
37
|
-
;
|
|
38
|
-
|
|
74
|
+
case "param": {
|
|
75
|
+
const paramsNames = [match.value];
|
|
76
|
+
let numberOfParams = 1;
|
|
77
|
+
while (i < matches.length && matches[i + 1]?._tag === "param") {
|
|
78
|
+
numberOfParams++;
|
|
79
|
+
i++;
|
|
80
|
+
paramsNames.push(matches[i].value);
|
|
81
|
+
}
|
|
82
|
+
if (!(numberOfParams in pathNavigator.params)) {
|
|
83
|
+
pathNavigator.params[numberOfParams] = new PathsTree(`${pathNavigator.path}:${paramsNames.join("/:")}/`);
|
|
84
|
+
}
|
|
85
|
+
pathNavigator = pathNavigator.params[numberOfParams];
|
|
86
|
+
i++;
|
|
87
|
+
break;
|
|
39
88
|
}
|
|
40
|
-
pathNavigator = (pathNavigator)[numberOfParams];
|
|
41
|
-
i++;
|
|
42
|
-
break;
|
|
43
89
|
}
|
|
44
90
|
}
|
|
91
|
+
if (pathNavigator.methods.includes(path.method)) {
|
|
92
|
+
// throw duplicate path-method error
|
|
93
|
+
return yield* $(tsplus_module_1.fail(new InvalidStateError(`Duplicate method ${path.method} for path ${path.path}`)));
|
|
94
|
+
}
|
|
95
|
+
pathNavigator.methods.push(path.method);
|
|
45
96
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return tsplus_module_1.fail(new InvalidStateError(`Duplicate method ${path.method} for path ${path.path}`));
|
|
49
|
-
}
|
|
50
|
-
pathNavigator[methods].push(path.method);
|
|
51
|
-
}
|
|
52
|
-
return tsplus_module_1.succeed(paths);
|
|
97
|
+
return paths;
|
|
98
|
+
});
|
|
53
99
|
}
|
|
54
100
|
/**
|
|
55
101
|
* Work in progress JSONSchema generator.
|
|
56
102
|
*/
|
|
57
103
|
export function makeJsonSchema(r) {
|
|
58
|
-
return tsplus_module_1.map(tsplus_module_1.flatMap(tsplus_module_3.ext_forEach(tsplus_module_2.fromIterable(r), RS.makeFromSchema),
|
|
104
|
+
return tsplus_module_1.map(tsplus_module_1.flatMap(tsplus_module_3.ext_forEach(tsplus_module_2.fromIterable(r), RS.makeFromSchema), checkPaths), (e) => {
|
|
59
105
|
const map = ({ method, path, responses, ...rest }) => ({
|
|
60
106
|
[method]: {
|
|
61
107
|
...rest,
|
|
@@ -82,4 +128,4 @@ class Response {
|
|
|
82
128
|
this.type = type;
|
|
83
129
|
}
|
|
84
130
|
}
|
|
85
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
131
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFrZUpzb25TY2hlbWEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9fc3JjL2FwaS9leHByZXNzL21ha2VKc29uU2NoZW1hLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHVEQUF1RDtBQUV2RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUNuRCxPQUFPLEtBQUssRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBSXpDLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQTtBQUlwQixNQUFNLFNBQVM7SUFNYixZQUFZLElBQVk7UUFDdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUE7UUFDakIsSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFLENBQUE7UUFDaEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxFQUFFLENBQUE7UUFDbEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUE7SUFDbEIsQ0FBQztDQUNGO0FBRUQsb0JBQW9CO0FBQ3BCLCtCQUErQjtBQUMvQixrQkFBa0I7QUFDbEIsSUFBSTtBQUVKLDJCQUEyQjtBQUMzQiw4QkFBOEI7QUFDOUIsaUJBQWlCO0FBQ2pCLE1BQU07QUFDTixxQ0FBcUM7QUFDckMsNEJBQTRCO0FBQzVCLDJCQUEyQjtBQUMzQix1RkFBdUY7QUFDdkYseUNBQXlDO0FBQ3pDLHlDQUF5QztBQUN6QyxxQ0FBcUM7QUFDckMsMkdBQTJHO0FBQzNHLGdCQUFnQjtBQUNoQixlQUFlO0FBQ2YsWUFBWTtBQUNaLGdCQUFnQjtBQUNoQixVQUFVO0FBQ1Ysd0JBQXdCO0FBQ3hCLHNHQUFzRztBQUN0Ryw4RUFBOEU7QUFDOUUscUNBQXFDO0FBQ3JDLG1EQUFtRDtBQUNuRCw4QkFBOEI7QUFDOUIseUhBQXlIO0FBQ3pILGdCQUFnQjtBQUNoQixlQUFlO0FBQ2YsWUFBWTtBQUNaLGdCQUFnQjtBQUNoQixVQUFVO0FBQ1YsUUFBUTtBQUNSLE9BQU87QUFDUCxJQUFJO0FBRUosTUFB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
|
|
@@ -18,7 +18,7 @@ export declare function makeOpenApiSpecs(rdescs: Iterable<RouteDescriptorAny>, i
|
|
|
18
18
|
version: string;
|
|
19
19
|
};
|
|
20
20
|
tags: never[];
|
|
21
|
-
paths: Record<string, Record<"
|
|
21
|
+
paths: Record<string, Record<"GET" | "PUT" | "POST" | "PATCH" | "DELETE", {
|
|
22
22
|
[x: string]: {
|
|
23
23
|
responses: any;
|
|
24
24
|
tags: readonly string[] | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"proper-lockfile": "^4.1.2",
|
|
20
20
|
"pure-rand": "^6.0.2",
|
|
21
21
|
"redlock": "^4.2.0",
|
|
22
|
-
"@effect-app/core": "0.56.1",
|
|
23
22
|
"@effect-app/infra-adapters": "0.49.2",
|
|
23
|
+
"@effect-app/core": "0.56.1",
|
|
24
24
|
"@effect-app/schema": "0.50.1",
|
|
25
25
|
"@effect-app/prelude": "0.58.2"
|
|
26
26
|
},
|