@adhd/apigen-plugin-openapi 0.2.2 → 0.2.3
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 +4 -0
- package/index.js +1 -1
- package/index.mjs +43 -42
- package/package.json +22 -4
package/CHANGELOG.md
CHANGED
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require("
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require("node:fs");const v=require("node:module");require("node:path");var c=typeof document<"u"?document.currentScript:null;function m(e){return{raw:e,words:e.split(/(?=[A-Z])|[-_]/).map(t=>t.toLowerCase()).filter(Boolean)}}function O(e,t,n={}){const o=e.split("/");if(o.length<2||o.some(f=>f.length===0))throw new Error(`syntheticOp: id "${e}" must be "<namespace>/<path...>" with non-empty segments`);const[r,...i]=o,l=r.replace(/^_+/,""),a=n.kind??"action",s={id:e,host:t.host,namespace:m(l),path:i.map(m),kind:a,async:n.async??!1,streaming:n.streaming??!1,safe:n.safe??a==="query",input:n.input??{},output:n.output??{},envelope:n.envelope??{},typeText:n.typeText??null};return n.hasCtx!==void 0&&(s.hasCtx=n.hasCtx),n.transports!==void 0&&(s.transports=n.transports),s}v.createRequire(typeof document>"u"?require("url").pathToFileURL(__filename).href:c&&c.tagName.toUpperCase()==="SCRIPT"&&c.src||new URL("index.js",document.baseURI).href);const q={"decimal.js":"Decimal"};function _(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(q).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${_(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));v.createRequire(typeof document>"u"?require("url").pathToFileURL(__filename).href:c&&c.tagName.toUpperCase()==="SCRIPT"&&c.src||new URL("index.js",document.baseURI).href);const y=new Set(["string","number","boolean","integer"]);function R(e){if(typeof e!="object"||e===null)return!1;const t=e;if(t.$ref!==void 0||t.oneOf||t.anyOf||t.allOf)return!1;const{type:n}=t;return typeof n=="string"?y.has(n):Array.isArray(n)?n.every(o=>y.has(o)||o==="null"):Array.isArray(t.enum)&&t.enum.length>0?t.enum.every(o=>["string","number","boolean"].includes(typeof o)):!1}function A(e){if(!e||typeof e!="object")return!1;const t=e.properties;return t===void 0||typeof t!="object"||t===null?!1:Object.values(t).every(R)}const S={"decimal.js":"Decimal"};function C(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(S).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${C(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));function h(e){return e.words.join("-")}function g(e){return e.words.map(T).join("")}function b(e){return e.words.join("_")}function P(e,t={}){var n,o;const r=[e.namespace,...e.path],i=e.safe||A(e.input)?"GET":"POST",l=((o=(n=t.http)==null?void 0:n.verb)==null?void 0:o[e.id])??i,a="/"+r.map(p=>h(p)).join("/"),s=r.map(p=>b(p)).join("_"),f=r.map(p=>b(p)).slice(0,-1).join("."),d=g(r[r.length-2]??r[0]),u=g(r[r.length-1]),w=r.map(p=>h(p));return{http:{verb:l,route:a},mcp:{name:s},grpc:{package:f,service:d,method:u},cli:{path:w}}}function T(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function x(e,t={}){const n=t.title??"API",o=t.version??"0.0.0",r={};for(const i of e){const l=P(i),{verb:a,route:s}=l.http,f=a.toLowerCase(),d={operationId:i.id,summary:i.id,responses:{200:I(i.output)}};if(a==="GET")d.parameters=U(i.input);else{const u=i.input;typeof u=="object"&&u!==null&&Object.keys(u).length>0&&(d.requestBody={required:!0,content:{"application/json":{schema:u}}})}r[s]===void 0&&(r[s]={}),r[s][f]=d}return{openapi:"3.1.0",info:{title:n,version:o},paths:r}}function I(e){return typeof e=="object"&&e!==null&&Object.keys(e).length>0?{description:"Success",content:{"application/json":{schema:e}}}:{description:"Success"}}function U(e){if(typeof e!="object"||e===null||typeof e.properties!="object"||e.properties===null)return[];const t=Array.isArray(e.required)?e.required:[],n=e.properties;return Object.entries(n).map(([o,r])=>({name:o,in:"query",required:t.includes(o),schema:r}))}function k(e,t={}){return[{...O("_meta/openapi",e,{kind:"query",safe:!0,output:{type:"object"},transports:["http"]}),handler:n=>x(e.operations,{title:t.title,version:t.version})}]}const j={id:"openapi",description:"Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",language:"ts",optionsSchema:{type:"object",properties:{title:{type:"string",description:"OpenAPI info.title"},version:{type:"string",description:"OpenAPI info.version"}},additionalProperties:!1},capabilities:{mount:{operations(e,t){return k(e,t)}}}};exports.default=j;exports.openapiPlugin=j;
|
package/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import "ts-morph";
|
|
2
1
|
import "node:fs";
|
|
2
|
+
import { createRequire as b } from "node:module";
|
|
3
3
|
import "node:path";
|
|
4
|
-
import "ts-json-schema-generator";
|
|
5
4
|
function m(e) {
|
|
6
5
|
return {
|
|
7
6
|
raw: e,
|
|
@@ -9,16 +8,16 @@ function m(e) {
|
|
|
9
8
|
};
|
|
10
9
|
}
|
|
11
10
|
function j(e, t, n = {}) {
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
11
|
+
const r = e.split("/");
|
|
12
|
+
if (r.length < 2 || r.some((l) => l.length === 0))
|
|
14
13
|
throw new Error(
|
|
15
14
|
`syntheticOp: id "${e}" must be "<namespace>/<path...>" with non-empty segments`
|
|
16
15
|
);
|
|
17
|
-
const [o, ...
|
|
16
|
+
const [o, ...i] = r, c = o.replace(/^_+/, ""), p = n.kind ?? "action", s = {
|
|
18
17
|
id: e,
|
|
19
18
|
host: t.host,
|
|
20
19
|
namespace: m(c),
|
|
21
|
-
path:
|
|
20
|
+
path: i.map(m),
|
|
22
21
|
kind: p,
|
|
23
22
|
async: n.async ?? !1,
|
|
24
23
|
streaming: n.streaming ?? !1,
|
|
@@ -30,13 +29,14 @@ function j(e, t, n = {}) {
|
|
|
30
29
|
};
|
|
31
30
|
return n.hasCtx !== void 0 && (s.hasCtx = n.hasCtx), n.transports !== void 0 && (s.transports = n.transports), s;
|
|
32
31
|
}
|
|
33
|
-
|
|
32
|
+
b(import.meta.url);
|
|
33
|
+
const O = {
|
|
34
34
|
"decimal.js": "Decimal"
|
|
35
35
|
};
|
|
36
|
-
function
|
|
36
|
+
function w(e) {
|
|
37
37
|
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38
38
|
}
|
|
39
|
-
Object.entries(
|
|
39
|
+
Object.entries(O).map(([e, t]) => ({
|
|
40
40
|
// Matches: import("...{modSpec}...").<anyMemberName> (single or double quotes)
|
|
41
41
|
// The module specifier appears inside an absolute path, so we allow any
|
|
42
42
|
// characters between the quote and the specifier, and between the specifier
|
|
@@ -44,36 +44,37 @@ Object.entries(v).map(([e, t]) => ({
|
|
|
44
44
|
// …) is matched generically (`\w+`) rather than anchored to one spelling —
|
|
45
45
|
// see the doc comment above for why.
|
|
46
46
|
pattern: new RegExp(
|
|
47
|
-
`import\\(["'][^"']*${
|
|
47
|
+
`import\\(["'][^"']*${w(e)}[^"']*["']\\)\\.\\w+`,
|
|
48
48
|
"g"
|
|
49
49
|
),
|
|
50
50
|
key: t
|
|
51
51
|
}));
|
|
52
|
+
b(import.meta.url);
|
|
52
53
|
const d = /* @__PURE__ */ new Set(["string", "number", "boolean", "integer"]);
|
|
53
|
-
function
|
|
54
|
+
function A(e) {
|
|
54
55
|
if (typeof e != "object" || e === null)
|
|
55
56
|
return !1;
|
|
56
57
|
const t = e;
|
|
57
58
|
if (t.$ref !== void 0 || t.oneOf || t.anyOf || t.allOf)
|
|
58
59
|
return !1;
|
|
59
60
|
const { type: n } = t;
|
|
60
|
-
return typeof n == "string" ? d.has(n) : Array.isArray(n) ? n.every((
|
|
61
|
+
return typeof n == "string" ? d.has(n) : Array.isArray(n) ? n.every((r) => d.has(r) || r === "null") : Array.isArray(t.enum) && t.enum.length > 0 ? t.enum.every((r) => ["string", "number", "boolean"].includes(typeof r)) : !1;
|
|
61
62
|
}
|
|
62
|
-
function
|
|
63
|
+
function q(e) {
|
|
63
64
|
if (!e || typeof e != "object")
|
|
64
65
|
return !1;
|
|
65
66
|
const t = e.properties;
|
|
66
67
|
return t === void 0 || typeof t != "object" || t === null ? !1 : Object.values(t).every(
|
|
67
|
-
|
|
68
|
+
A
|
|
68
69
|
);
|
|
69
70
|
}
|
|
70
|
-
const
|
|
71
|
+
const k = {
|
|
71
72
|
"decimal.js": "Decimal"
|
|
72
73
|
};
|
|
73
|
-
function
|
|
74
|
+
function x(e) {
|
|
74
75
|
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
75
76
|
}
|
|
76
|
-
Object.entries(
|
|
77
|
+
Object.entries(k).map(([e, t]) => ({
|
|
77
78
|
// Matches: import("...{modSpec}...").<anyMemberName> (single or double quotes)
|
|
78
79
|
// The module specifier appears inside an absolute path, so we allow any
|
|
79
80
|
// characters between the quote and the specifier, and between the specifier
|
|
@@ -81,7 +82,7 @@ Object.entries(q).map(([e, t]) => ({
|
|
|
81
82
|
// …) is matched generically (`\w+`) rather than anchored to one spelling —
|
|
82
83
|
// see the doc comment above for why.
|
|
83
84
|
pattern: new RegExp(
|
|
84
|
-
`import\\(["'][^"']*${
|
|
85
|
+
`import\\(["'][^"']*${x(e)}[^"']*["']\\)\\.\\w+`,
|
|
85
86
|
"g"
|
|
86
87
|
),
|
|
87
88
|
key: t
|
|
@@ -90,38 +91,38 @@ function y(e) {
|
|
|
90
91
|
return e.words.join("-");
|
|
91
92
|
}
|
|
92
93
|
function h(e) {
|
|
93
|
-
return e.words.map(
|
|
94
|
+
return e.words.map($).join("");
|
|
94
95
|
}
|
|
95
96
|
function g(e) {
|
|
96
97
|
return e.words.join("_");
|
|
97
98
|
}
|
|
98
|
-
function
|
|
99
|
-
var n,
|
|
100
|
-
const o = [e.namespace, ...e.path],
|
|
99
|
+
function _(e, t = {}) {
|
|
100
|
+
var n, r;
|
|
101
|
+
const o = [e.namespace, ...e.path], i = e.safe || q(e.input) ? "GET" : "POST", c = ((r = (n = t.http) == null ? void 0 : n.verb) == null ? void 0 : r[e.id]) ?? i, p = "/" + o.map((a) => y(a)).join("/"), s = o.map((a) => g(a)).join("_"), l = o.map((a) => g(a)).slice(0, -1).join("."), f = h(o[o.length - 2] ?? o[0]), u = h(o[o.length - 1]), v = o.map((a) => y(a));
|
|
101
102
|
return {
|
|
102
103
|
http: { verb: c, route: p },
|
|
103
104
|
mcp: { name: s },
|
|
104
105
|
grpc: { package: l, service: f, method: u },
|
|
105
|
-
cli: { path:
|
|
106
|
+
cli: { path: v }
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
|
-
function
|
|
109
|
+
function $(e) {
|
|
109
110
|
return e.length === 0 ? e : e[0].toUpperCase() + e.slice(1);
|
|
110
111
|
}
|
|
111
|
-
function
|
|
112
|
-
const n = t.title ?? "API",
|
|
113
|
-
for (const
|
|
114
|
-
const c =
|
|
115
|
-
operationId:
|
|
116
|
-
summary:
|
|
112
|
+
function E(e, t = {}) {
|
|
113
|
+
const n = t.title ?? "API", r = t.version ?? "0.0.0", o = {};
|
|
114
|
+
for (const i of e) {
|
|
115
|
+
const c = _(i), { verb: p, route: s } = c.http, l = p.toLowerCase(), f = {
|
|
116
|
+
operationId: i.id,
|
|
117
|
+
summary: i.id,
|
|
117
118
|
responses: {
|
|
118
|
-
200:
|
|
119
|
+
200: P(i.output)
|
|
119
120
|
}
|
|
120
121
|
};
|
|
121
122
|
if (p === "GET")
|
|
122
|
-
f.parameters = C(
|
|
123
|
+
f.parameters = C(i.input);
|
|
123
124
|
else {
|
|
124
|
-
const u =
|
|
125
|
+
const u = i.input;
|
|
125
126
|
typeof u == "object" && u !== null && Object.keys(u).length > 0 && (f.requestBody = {
|
|
126
127
|
required: !0,
|
|
127
128
|
content: {
|
|
@@ -135,11 +136,11 @@ function $(e, t = {}) {
|
|
|
135
136
|
}
|
|
136
137
|
return {
|
|
137
138
|
openapi: "3.1.0",
|
|
138
|
-
info: { title: n, version:
|
|
139
|
+
info: { title: n, version: r },
|
|
139
140
|
paths: o
|
|
140
141
|
};
|
|
141
142
|
}
|
|
142
|
-
function
|
|
143
|
+
function P(e) {
|
|
143
144
|
return typeof e == "object" && e !== null && Object.keys(e).length > 0 ? {
|
|
144
145
|
description: "Success",
|
|
145
146
|
content: {
|
|
@@ -151,10 +152,10 @@ function C(e) {
|
|
|
151
152
|
if (typeof e != "object" || e === null || typeof e.properties != "object" || e.properties === null)
|
|
152
153
|
return [];
|
|
153
154
|
const t = Array.isArray(e.required) ? e.required : [], n = e.properties;
|
|
154
|
-
return Object.entries(n).map(([
|
|
155
|
-
name:
|
|
155
|
+
return Object.entries(n).map(([r, o]) => ({
|
|
156
|
+
name: r,
|
|
156
157
|
in: "query",
|
|
157
|
-
required: t.includes(
|
|
158
|
+
required: t.includes(r),
|
|
158
159
|
schema: o
|
|
159
160
|
}));
|
|
160
161
|
}
|
|
@@ -172,14 +173,14 @@ function S(e, t = {}) {
|
|
|
172
173
|
transports: ["http"]
|
|
173
174
|
}),
|
|
174
175
|
// Handler: derive the doc from the descriptor at request time.
|
|
175
|
-
handler: (n) =>
|
|
176
|
+
handler: (n) => E(e.operations, {
|
|
176
177
|
title: t.title,
|
|
177
178
|
version: t.version
|
|
178
179
|
})
|
|
179
180
|
}
|
|
180
181
|
];
|
|
181
182
|
}
|
|
182
|
-
const
|
|
183
|
+
const G = {
|
|
183
184
|
id: "openapi",
|
|
184
185
|
description: "Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",
|
|
185
186
|
language: "ts",
|
|
@@ -203,6 +204,6 @@ const B = {
|
|
|
203
204
|
}
|
|
204
205
|
};
|
|
205
206
|
export {
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
G as default,
|
|
208
|
+
G as openapiPlugin
|
|
208
209
|
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhd/apigen-plugin-openapi",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@adhd/apigen-core-client": "^0.3.
|
|
7
|
-
"@adhd/apigen-codegen-openapi": "^0.2.
|
|
6
|
+
"@adhd/apigen-core-client": "^0.3.1",
|
|
7
|
+
"@adhd/apigen-codegen-openapi": "^0.2.3"
|
|
8
8
|
},
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
12
|
"module": "./index.mjs",
|
|
13
|
-
"types": "./index.d.ts"
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"description": "apigen plugin that live-mounts TypeScript as an OpenAPI document",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"openapi",
|
|
17
|
+
"apigen",
|
|
18
|
+
"typescript",
|
|
19
|
+
"plugin",
|
|
20
|
+
"codegen"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/PseudoSky/adhd.git",
|
|
26
|
+
"directory": "packages/apigen/apigen-plugin-openapi"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/PseudoSky/adhd/tree/main/packages/apigen/apigen-plugin-openapi#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/PseudoSky/adhd/issues"
|
|
31
|
+
}
|
|
14
32
|
}
|