@adhd/apigen-plugin-openapi 0.1.1 → 0.1.2

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
@@ -10,5 +10,5 @@ npx @adhd/apigen-cli generate --source ./api.ts --type openapi --out-dir ./out
10
10
  ```
11
11
 
12
12
  ```ts
13
- import { openapiPlugin, type OpenapiOptions } from '@adhd/apigen-plugin-openapi'
13
+ import { openapiPlugin, type OpenapiOptions } from '@adhd/apigen-plugin-openapi';
14
14
  ```
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function m(e){return e.words.join("-")}function g(e){return e.words.map(P).join("")}function b(e){return e.words.join("_")}function v(e,t={}){var d,h;const n=[e.namespace,...e.path],s=e.safe?"GET":"POST",r=((h=(d=t.http)==null?void 0:d.verb)==null?void 0:h[e.id])??s,o="/"+n.map(i=>m(i)).join("/"),l=n.map(i=>b(i)).join("_"),p=n.map(i=>b(i)).slice(0,-1).join("."),u=g(n[n.length-2]??n[0]),c=g(n[n.length-1]),a=n.map(i=>m(i));return{http:{verb:r,route:o},mcp:{name:l},grpc:{package:p,service:u,method:c},cli:{path:a}}}function P(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function O(e,t={}){const n=t.title??"API",s=t.version??"0.0.0",r={};for(const o of e){const l=v(o),{verb:f,route:p}=l.http,u=f.toLowerCase(),c={operationId:o.id,summary:o.id,responses:{200:S(o.output)}};if(o.safe)c.parameters=q(o.input);else{const a=o.input;typeof a=="object"&&a!==null&&Object.keys(a).length>0&&(c.requestBody={required:!0,content:{"application/json":{schema:a}}})}r[p]===void 0&&(r[p]={}),r[p][u]=c}return{openapi:"3.1.0",info:{title:n,version:s},paths:r}}function S(e){return typeof e=="object"&&e!==null&&Object.keys(e).length>0?{description:"Success",content:{"application/json":{schema:e}}}:{description:"Success"}}function q(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(([s,r])=>({name:s,in:"query",required:t.includes(s),schema:r}))}function y(e){return{raw:e,words:e.split(/(?=[A-Z])|[-_]/).map(t=>t.toLowerCase()).filter(Boolean)}}function A(e,t={}){return[{id:"_meta/openapi",host:e.host,namespace:y("meta"),path:[y("openapi")],kind:"query",async:!1,streaming:!1,safe:!0,input:{},output:{type:"object"},envelope:{},typeText:null,transports:["http"],handler:n=>O(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",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 A(e,t)}}}};exports.default=j;exports.openapiPlugin=j;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require("ts-morph");require("node:fs");require("node:path");require("ts-json-schema-generator");const d=new Set(["string","number","boolean","integer"]);function v(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:r}=t;return typeof r=="string"?d.has(r):Array.isArray(r)?r.every(o=>d.has(o)||o==="null"):Array.isArray(t.enum)&&t.enum.length>0?t.enum.every(o=>["string","number","boolean"].includes(typeof o)):!1}function O(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(v)}const q={"decimal.js":"Decimal"};function A(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(q).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${A(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));function m(e){return e.words.join("-")}function y(e){return e.words.map(w).join("")}function g(e){return e.words.join("_")}function P(e,t={}){var r,o;const n=[e.namespace,...e.path],i=e.safe||O(e.input)?"GET":"POST",c=((o=(r=t.http)==null?void 0:r.verb)==null?void 0:o[e.id])??i,l="/"+n.map(s=>m(s)).join("/"),a=n.map(s=>g(s)).join("_"),f=n.map(s=>g(s)).slice(0,-1).join("."),u=y(n[n.length-2]??n[0]),p=y(n[n.length-1]),j=n.map(s=>m(s));return{http:{verb:c,route:l},mcp:{name:a},grpc:{package:f,service:u,method:p},cli:{path:j}}}function w(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function S(e,t={}){const r=t.title??"API",o=t.version??"0.0.0",n={};for(const i of e){const c=P(i),{verb:l,route:a}=c.http,f=l.toLowerCase(),u={operationId:i.id,summary:i.id,responses:{200:_(i.output)}};if(l==="GET")u.parameters=k(i.input);else{const p=i.input;typeof p=="object"&&p!==null&&Object.keys(p).length>0&&(u.requestBody={required:!0,content:{"application/json":{schema:p}}})}n[a]===void 0&&(n[a]={}),n[a][f]=u}return{openapi:"3.1.0",info:{title:r,version:o},paths:n}}function _(e){return typeof e=="object"&&e!==null&&Object.keys(e).length>0?{description:"Success",content:{"application/json":{schema:e}}}:{description:"Success"}}function k(e){if(typeof e!="object"||e===null||typeof e.properties!="object"||e.properties===null)return[];const t=Array.isArray(e.required)?e.required:[],r=e.properties;return Object.entries(r).map(([o,n])=>({name:o,in:"query",required:t.includes(o),schema:n}))}function b(e){return{raw:e,words:e.split(/(?=[A-Z])|[-_]/).map(t=>t.toLowerCase()).filter(Boolean)}}function T(e,t={}){return[{id:"_meta/openapi",host:e.host,namespace:b("meta"),path:[b("openapi")],kind:"query",async:!1,streaming:!1,safe:!0,input:{},output:{type:"object"},envelope:{},typeText:null,transports:["http"],handler:r=>S(e.operations,{title:t.title,version:t.version})}]}const h={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 T(e,t)}}}};exports.default=h;exports.openapiPlugin=h;
package/index.mjs CHANGED
@@ -1,40 +1,81 @@
1
- function m(e) {
1
+ import "ts-morph";
2
+ import "node:fs";
3
+ import "node:path";
4
+ import "ts-json-schema-generator";
5
+ const m = /* @__PURE__ */ new Set(["string", "number", "boolean", "integer"]);
6
+ function j(e) {
7
+ if (typeof e != "object" || e === null)
8
+ return !1;
9
+ const t = e;
10
+ if (t.$ref !== void 0 || t.oneOf || t.anyOf || t.allOf)
11
+ return !1;
12
+ const { type: o } = t;
13
+ return typeof o == "string" ? m.has(o) : Array.isArray(o) ? o.every((r) => m.has(r) || r === "null") : Array.isArray(t.enum) && t.enum.length > 0 ? t.enum.every((r) => ["string", "number", "boolean"].includes(typeof r)) : !1;
14
+ }
15
+ function v(e) {
16
+ if (!e || typeof e != "object")
17
+ return !1;
18
+ const t = e.properties;
19
+ return t === void 0 || typeof t != "object" || t === null ? !1 : Object.values(t).every(
20
+ j
21
+ );
22
+ }
23
+ const O = {
24
+ "decimal.js": "Decimal"
25
+ };
26
+ function A(e) {
27
+ return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28
+ }
29
+ Object.entries(O).map(([e, t]) => ({
30
+ // Matches: import("...{modSpec}...").<anyMemberName> (single or double quotes)
31
+ // The module specifier appears inside an absolute path, so we allow any
32
+ // characters between the quote and the specifier, and between the specifier
33
+ // and the closing quote. The trailing member accessor (`.default`, `.Decimal`,
34
+ // …) is matched generically (`\w+`) rather than anchored to one spelling —
35
+ // see the doc comment above for why.
36
+ pattern: new RegExp(
37
+ `import\\(["'][^"']*${A(e)}[^"']*["']\\)\\.\\w+`,
38
+ "g"
39
+ ),
40
+ key: t
41
+ }));
42
+ function d(e) {
2
43
  return e.words.join("-");
3
44
  }
4
45
  function y(e) {
5
- return e.words.map(v).join("");
46
+ return e.words.map(w).join("");
6
47
  }
7
- function b(e) {
48
+ function h(e) {
8
49
  return e.words.join("_");
9
50
  }
10
- function j(e, t = {}) {
11
- var f, h;
12
- const n = [e.namespace, ...e.path], s = e.safe ? "GET" : "POST", r = ((h = (f = t.http) == null ? void 0 : f.verb) == null ? void 0 : h[e.id]) ?? s, o = "/" + n.map((i) => m(i)).join("/"), l = n.map((i) => b(i)).join("_"), a = n.map((i) => b(i)).slice(0, -1).join("."), u = y(n[n.length - 2] ?? n[0]), c = y(n[n.length - 1]), p = n.map((i) => m(i));
51
+ function q(e, t = {}) {
52
+ var o, r;
53
+ const n = [e.namespace, ...e.path], i = e.safe || v(e.input) ? "GET" : "POST", l = ((r = (o = t.http) == null ? void 0 : o.verb) == null ? void 0 : r[e.id]) ?? i, c = "/" + n.map((s) => d(s)).join("/"), a = n.map((s) => h(s)).join("_"), f = n.map((s) => h(s)).slice(0, -1).join("."), u = y(n[n.length - 2] ?? n[0]), p = y(n[n.length - 1]), g = n.map((s) => d(s));
13
54
  return {
14
- http: { verb: r, route: o },
15
- mcp: { name: l },
16
- grpc: { package: a, service: u, method: c },
17
- cli: { path: p }
55
+ http: { verb: l, route: c },
56
+ mcp: { name: a },
57
+ grpc: { package: f, service: u, method: p },
58
+ cli: { path: g }
18
59
  };
19
60
  }
20
- function v(e) {
61
+ function w(e) {
21
62
  return e.length === 0 ? e : e[0].toUpperCase() + e.slice(1);
22
63
  }
23
64
  function P(e, t = {}) {
24
- const n = t.title ?? "API", s = t.version ?? "0.0.0", r = {};
25
- for (const o of e) {
26
- const l = j(o), { verb: d, route: a } = l.http, u = d.toLowerCase(), c = {
27
- operationId: o.id,
28
- summary: o.id,
65
+ const o = t.title ?? "API", r = t.version ?? "0.0.0", n = {};
66
+ for (const i of e) {
67
+ const l = q(i), { verb: c, route: a } = l.http, f = c.toLowerCase(), u = {
68
+ operationId: i.id,
69
+ summary: i.id,
29
70
  responses: {
30
- 200: O(o.output)
71
+ 200: k(i.output)
31
72
  }
32
73
  };
33
- if (o.safe)
34
- c.parameters = q(o.input);
74
+ if (c === "GET")
75
+ u.parameters = S(i.input);
35
76
  else {
36
- const p = o.input;
37
- typeof p == "object" && p !== null && Object.keys(p).length > 0 && (c.requestBody = {
77
+ const p = i.input;
78
+ typeof p == "object" && p !== null && Object.keys(p).length > 0 && (u.requestBody = {
38
79
  required: !0,
39
80
  content: {
40
81
  "application/json": {
@@ -43,15 +84,15 @@ function P(e, t = {}) {
43
84
  }
44
85
  });
45
86
  }
46
- r[a] === void 0 && (r[a] = {}), r[a][u] = c;
87
+ n[a] === void 0 && (n[a] = {}), n[a][f] = u;
47
88
  }
48
89
  return {
49
90
  openapi: "3.1.0",
50
- info: { title: n, version: s },
51
- paths: r
91
+ info: { title: o, version: r },
92
+ paths: n
52
93
  };
53
94
  }
54
- function O(e) {
95
+ function k(e) {
55
96
  return typeof e == "object" && e !== null && Object.keys(e).length > 0 ? {
56
97
  description: "Success",
57
98
  content: {
@@ -59,28 +100,31 @@ function O(e) {
59
100
  }
60
101
  } : { description: "Success" };
61
102
  }
62
- function q(e) {
103
+ function S(e) {
63
104
  if (typeof e != "object" || e === null || typeof e.properties != "object" || e.properties === null)
64
105
  return [];
65
- const t = Array.isArray(e.required) ? e.required : [], n = e.properties;
66
- return Object.entries(n).map(([s, r]) => ({
67
- name: s,
106
+ const t = Array.isArray(e.required) ? e.required : [], o = e.properties;
107
+ return Object.entries(o).map(([r, n]) => ({
108
+ name: r,
68
109
  in: "query",
69
- required: t.includes(s),
70
- schema: r
110
+ required: t.includes(r),
111
+ schema: n
71
112
  }));
72
113
  }
73
- function g(e) {
74
- return { raw: e, words: e.split(/(?=[A-Z])|[-_]/).map((t) => t.toLowerCase()).filter(Boolean) };
114
+ function b(e) {
115
+ return {
116
+ raw: e,
117
+ words: e.split(/(?=[A-Z])|[-_]/).map((t) => t.toLowerCase()).filter(Boolean)
118
+ };
75
119
  }
76
- function A(e, t = {}) {
120
+ function I(e, t = {}) {
77
121
  return [
78
122
  {
79
123
  // Canonical id — the `_meta` prefix is a convention for meta-endpoints.
80
124
  id: "_meta/openapi",
81
125
  host: e.host,
82
- namespace: g("meta"),
83
- path: [g("openapi")],
126
+ namespace: b("meta"),
127
+ path: [b("openapi")],
84
128
  // query + safe → GET /meta/openapi (SPEC §5)
85
129
  kind: "query",
86
130
  async: !1,
@@ -96,16 +140,17 @@ function A(e, t = {}) {
96
140
  // Expose only on HTTP — the doc is a tooling artefact (SPEC §7.2b).
97
141
  transports: ["http"],
98
142
  // Handler: derive the doc from the descriptor at request time.
99
- handler: (n) => P(e.operations, {
143
+ handler: (o) => P(e.operations, {
100
144
  title: t.title,
101
145
  version: t.version
102
146
  })
103
147
  }
104
148
  ];
105
149
  }
106
- const S = {
150
+ const x = {
107
151
  id: "openapi",
108
152
  description: "Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",
153
+ language: "ts",
109
154
  optionsSchema: {
110
155
  type: "object",
111
156
  properties: {
@@ -117,12 +162,15 @@ const S = {
117
162
  capabilities: {
118
163
  mount: {
119
164
  operations(e, t) {
120
- return A(e, t);
165
+ return I(
166
+ e,
167
+ t
168
+ );
121
169
  }
122
170
  }
123
171
  }
124
172
  };
125
173
  export {
126
- S as default,
127
- S as openapiPlugin
174
+ x as default,
175
+ x as openapiPlugin
128
176
  };
package/lib/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Plugin } from '@adhd/apigen-core';
1
+ import { Plugin } from '@adhd/apigen-core-client';
2
2
 
3
3
  /** Options accepted by the openapi mount plugin. */
4
4
  export interface OpenapiOptions {
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@adhd/apigen-plugin-openapi",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "main": "./index.js",
5
5
  "dependencies": {
6
- "@adhd/apigen-core": "^0.1.0",
7
- "@adhd/apigen-codegen-openapi": "^0.1.0"
6
+ "@adhd/apigen-core-client": "^0.1.0",
7
+ "@adhd/apigen-codegen-openapi": "^0.1.2"
8
8
  },
9
9
  "publishConfig": {
10
10
  "access": "public"