@arpc-packages/schema-gen
Advanced tools
Comparing version 0.2.3 to 0.2.4
@@ -1,3 +0,3 @@ | ||
"use strict";var N=Object.create;var _=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var tt=Object.getPrototypeOf,et=Object.prototype.hasOwnProperty;var nt=(t,e)=>{for(var i in e)_(t,i,{get:e[i],enumerable:!0})},B=(t,e,i,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let u of q(e))!et.call(t,u)&&u!==i&&_(t,u,{get:()=>e[u],enumerable:!(a=W(e,u))||a.enumerable});return t};var J=(t,e,i)=>(i=t!=null?N(tt(t)):{},B(e||!t||!t.__esModule?_(i,"default",{value:t,enumerable:!0}):i,t)),it=t=>B(_({},"__esModule",{value:!0}),t);var at={};nt(at,{generateSchema:()=>H});module.exports=it(at);var U=require("fs/promises"),S=require("path"),Y=require("@arpc-packages/lockfile"),o=require("typescript"),G=J(require("zod"));var K=[{name:"BadRequest",description:"Thrown when a request is invalid."},{name:"Ratelimited",description:"Thrown when a user is ratelimited."},{name:"Unauthorized",description:"Thrown when a user is not authorized."},{name:"InternalServerError",description:"Thrown when the server encounters an internal error."}];var c=J(require("zod"));function R(t,e,i,a,u){if(t instanceof c.default.ZodString)return{type:"string"};if(t instanceof c.default.ZodNumber)return{type:"number"};if(t instanceof c.default.ZodBigInt)return{type:"bigint"};if(t instanceof c.default.ZodBoolean)return{type:"boolean"};if(t instanceof c.default.ZodNullable||t instanceof c.default.ZodOptional)return{type:"nullable",inner:R(t._def.innerType,e,i,a,u)};if(t instanceof c.default.ZodArray)return{type:"array",inner:R(t._def.type,e,i,a,u)};if(t instanceof c.default.ZodUnion){let m=function(T){for(let l of T.options)l instanceof c.default.ZodUnion?m(l):d.push(l)};var C=m;let d=[];return m(t),{type:"union",inner:d.map((T,l)=>R(T,e,i,a,()=>`${u()}Variant${l}`))}}if(t instanceof c.default.ZodRecord||t instanceof c.default.ZodMap)return{type:"map",key:R(t._def.keyType,e,i,a,u),value:R(t._def.valueType,e,i,a,u)};if(t instanceof c.default.ZodObject){let d={};for(let[h,x]of Object.entries(t.shape))d[h]=R(x,e,i,a,()=>`${u()}${h[0].toUpperCase()}${h.slice(1)}`);let m=u(),T=1,l=m;for(;a.has(l);){let h=i.find(x=>x.name===l);if(h&&JSON.stringify(h.fields)===JSON.stringify(d))return{type:"object",key:l};T++,l=`${m}V${T}`}return a.add(l),i.push({name:l,fields:d}),{type:"object",key:l}}if(t instanceof c.default.ZodEnum){let d=t.Enum,m=Object.keys(d),T=new Map;for(let z of m)T.set(z.replaceAll(" ","").replace(/[^a-zA-Z0-9_]/g,"_"),d[z]);let l={type:"string"};if(m.length!==0){let z=["string","number","bigint","boolean"],O=typeof d[m[0]];if(!z.includes(O))throw new Error("Enums can only have string, number, bigint, or boolean values");l={type:O}}let h=u(),x=1,Z=h;for(;a.has(Z);){let z=e.find(O=>O.name===Z);if(z&&JSON.stringify(z.data)===JSON.stringify(T))return{type:"enum_value",enum:Z};x++,Z=`${h}V${x}`}return a.add(Z),e.push({name:Z,valueType:l,data:T}),{type:"enum_value",enum:Z}}if(t instanceof c.default.ZodNull||t instanceof c.default.ZodUndefined)return{type:"literal",value:null};if(t instanceof c.default.ZodLiteral)return{type:"literal",value:t.value};throw new Error(`arpc doesn't support the type ${t.constructor.name} yet`)}var ot=/^(["'`])(.*)\1$/;function j(t){let e=ot.exec(t);return e?e[2]:t}function L(t,e){for(let i of Object.values(t)){if(typeof i!="string"){L(i,e);continue}e.has(i)||e.add(i)}}var rt=/^TokenTypes\.([A-Za-z0-9_]+)$/;function st(t){if(t==="undefined")return;let e=rt.exec(t||"");if(!e)throw new Error(`Invalid token type: ${t}`);return e[1]}function $(t){return t?typeof t=="string"?t:"escapedText"in t?t.escapedText:t.getText():""}async function H(t){let e=(0,S.join)(process.cwd(),"rpc"),i=(0,Y.parse)(await(0,U.readFile)((0,S.join)(e,"index.ts"),"utf-8")),a=[(0,S.join)(e,"index.ts")];i.hasAuthentication&&a.push((0,S.join)(e,"authentication.ts")),i.hasRatelimiting&&a.push((0,S.join)(e,"ratelimiting.ts"));let u=new Set;L(i.routes,u),L(i.exceptions,u);for(let s of u)a.push((0,S.join)(e,s));let C=(0,o.createProgram)(a,{allowJs:!0,alwaysStrict:!1}),d=null;if(i.hasAuthentication){let s=C.getSourceFile((0,S.join)(e,"authentication.ts"));if(!s)throw new Error("Failed to parse rpc/authentication.ts");let r=null,E=null;if(d=s.forEachChild(f=>{if((0,o.isEnumDeclaration)(f)&&f.name.text==="TokenTypes"){r={};for(let p of f.members){let w=j($(p.name));if(!p.initializer||!(0,o.isStringLiteral)(p.initializer))throw new Error(`TokenTypes.${w} must be a string literal`);r[w]=j($(p.initializer))}return E!==null?{tokenTypes:r,defaultTokenType:E}:void 0}if((0,o.isVariableStatement)(f)){let p=f.declarationList.declarations;if(p.length===1){let w=p[0];if($(w.name)==="defaultTokenType"&&(E=st($(w.initializer)),r))return{tokenTypes:r,defaultTokenType:E}}}})||null,r)d||(d={tokenTypes:r});else throw new Error("Failed to find TokenTypes enum in rpc/authentication.ts")}let m=[],T=Object.keys(i.exceptions).sort();for(let s of T){let r=(0,S.join)(e,i.exceptions[s]+".ts"),E=C.getSourceFile(r);if(!E)throw new Error(`Failed to parse ${r}`);let f=E.forEachChild(y=>{if((0,o.isClassDeclaration)(y)&&y.name?.text===s)return y});if(!f)throw new Error(`Failed to find class ${s} in ${r}`);let p=null,w=f.getFullStart(),k=f.getStart();if(w!==k){let y=E.getFullText(),g=(0,o.getLeadingCommentRanges)(y,k);g&&(p=y.substring(g[0].pos,g[0].end).trim())}m.push({name:s,description:p||`A ${s} custom exception`})}let l=t._routes,h=[],x=[],Z=new Set;function z(s,r,E){let f=(l||{})[E],p=null,w=null,k,y=0;for(;f;){let n=f[r[y]];if(n.input&&n.input instanceof G.default.ZodType){p=n.input,w=n.output,k=n.mutation;break}f=n,y++}if(!p||!w)throw new Error("Lockfile and router routes are out of sync");let g=new Map;s.forEachChild(n=>{(0,o.isTypeAliasDeclaration)(n)&&g.set(n.name.text,$(n.type))});for(let[n,b]of g){for(;g.has(b);)b=g.get(b);g.set(n,b)}let v=s.forEachChild(n=>{if((0,o.isVariableStatement)(n)){let b=n.declarationList.declarations;if(b.length!==1)return;let A=b[0];if($(A.name)==="method"){if(A.initializer&&((0,o.isArrowFunction)(A.initializer)||(0,o.isFunctionExpression)(A.initializer)))return A.initializer;throw new Error("method must be an arrow function or function expression")}}if(((0,o.isMethodDeclaration)(n)||(0,o.isFunctionDeclaration)(n))&&$(n.name)==="method")return n});if(!v)throw new Error("Failed to find method");let F=v.parameters[0];if(!F)throw new Error("Method must have at least one argument");let M=null;if(F.type){let n=$(F.type);if(n!=="z.infer<typeof input>"){if(g.get(n)!=="z.infer<typeof input>")throw new Error(`Method argument must be of type or alias a type that is equal to z.infer<typeof input> in the same file, got ${n}`);M=n}}let P={name:$(F.name),signature:R(p,h,x,Z,()=>M||r.map(n=>n[0].toUpperCase()+n.slice(1)).join("")+"Opts")},Q=R(w,h,x,Z,()=>r.map(n=>n[0].toUpperCase()+n.slice(1)).join("")+"Response"),D=null,X=v.getFullStart(),I=v.getStart();if(X!==I){let n=s.getFullText(),b=(0,o.getLeadingCommentRanges)(n,I);b&&(D=n.substring(b[0].pos,b[0].end).trim())}return k===void 0&&(k=!0),{input:P,output:Q,description:D,mutation:k}}let O=Object.keys(i.routes).sort(),V=[];for(let s of O){let p=function(w,k,y){for(let[g,v]of Object.entries(w)){if(typeof v!="string"){let P={};k[g]=P,y.push(g),p(v,P,y),y.pop();continue}let F=(0,S.join)(e,v+".ts"),M=C.getSourceFile(F);if(!M)throw new Error(`Failed to parse ${F}`);y.push(g),k[g]=z(M,y,s),y.pop()}};var ut=p;let r=null;try{r=await(0,U.readFile)((0,S.join)(e,"descriptions",`${s}.md`),"utf-8")}catch{}r===`You can write markdown here to describe your API version. | ||
`&&(r=null);let E=i.routes[s],f={};V.push({apiVersion:s,methods:f,description:r,defaultProtocol:"",defaultHostname:"",authentication:d}),p(E,f,[])}return{enums:h,objects:x,builtinExceptions:K,customExceptions:m,clients:V}}0&&(module.exports={generateSchema}); | ||
"use strict";var X=Object.create;var P=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,tt=Object.prototype.hasOwnProperty;var et=(t,e)=>{for(var i in e)P(t,i,{get:e[i],enumerable:!0})},I=(t,e,i,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let l of N(e))!tt.call(t,l)&&l!==i&&P(t,l,{get:()=>e[l],enumerable:!(a=W(e,l))||a.enumerable});return t};var B=(t,e,i)=>(i=t!=null?X(q(t)):{},I(e||!t||!t.__esModule?P(i,"default",{value:t,enumerable:!0}):i,t)),nt=t=>I(P({},"__esModule",{value:!0}),t);var st={};et(st,{generateSchema:()=>G});module.exports=nt(st);var j=require("fs/promises"),b=require("path"),K=require("@arpc-packages/lockfile"),o=require("typescript"),Y=B(require("zod"));var J=[{name:"BadRequest",description:"Thrown when a request is invalid."},{name:"Ratelimited",description:"Thrown when a user is ratelimited."},{name:"Unauthorized",description:"Thrown when a user is not authorized."},{name:"InternalServerError",description:"Thrown when the server encounters an internal error."}];var c=B(require("zod"));function R(t,e,i,a,l){if(t instanceof c.default.ZodString)return{type:"string"};if(t instanceof c.default.ZodNumber)return{type:"number"};if(t instanceof c.default.ZodBigInt)return{type:"bigint"};if(t instanceof c.default.ZodBoolean)return{type:"boolean"};if(t instanceof c.default.ZodNullable||t instanceof c.default.ZodOptional)return{type:"nullable",inner:R(t._def.innerType,e,i,a,l)};if(t instanceof c.default.ZodArray)return{type:"array",inner:R(t._def.type,e,i,a,l)};if(t instanceof c.default.ZodUnion){let m=function(w){for(let u of w.options)u instanceof c.default.ZodUnion?m(u):d.push(u)};var O=m;let d=[];return m(t),{type:"union",inner:d.map((w,u)=>R(w,e,i,a,()=>`${l()}Variant${u}`))}}if(t instanceof c.default.ZodRecord||t instanceof c.default.ZodMap)return{type:"map",key:R(t._def.keyType,e,i,a,l),value:R(t._def.valueType,e,i,a,l)};if(t instanceof c.default.ZodObject){let d={};for(let[h,S]of Object.entries(t.shape))d[h]=R(S,e,i,a,()=>`${l()}${h[0].toUpperCase()}${h.slice(1)}`);let m=l(),w=1,u=m;for(;a.has(u);){let h=i.find(S=>S.name===u);if(h&&JSON.stringify(h.fields)===JSON.stringify(d))return{type:"object",key:u};w++,u=`${m}V${w}`}return a.add(u),i.push({name:u,fields:d}),{type:"object",key:u}}if(t instanceof c.default.ZodEnum){let d=t.Enum,m=Object.keys(d),w=new Map;for(let z of m)w.set(z.replaceAll(" ","").replace(/[^a-zA-Z0-9_]/g,"_"),d[z]);let u={type:"string"};if(m.length!==0){let z=["string","number","bigint","boolean"],F=typeof d[m[0]];if(!z.includes(F))throw new Error("Enums can only have string, number, bigint, or boolean values");u={type:F}}let h=l(),S=1,k=h;for(;a.has(k);){let z=e.find(F=>F.name===k);if(z&&JSON.stringify(z.data)===JSON.stringify(w))return{type:"enum_value",enum:k};S++,k=`${h}V${S}`}return a.add(k),e.push({name:k,valueType:u,data:w}),{type:"enum_value",enum:k}}if(t instanceof c.default.ZodNull||t instanceof c.default.ZodUndefined)return{type:"literal",value:null};if(t instanceof c.default.ZodLiteral)return{type:"literal",value:t.value};throw new Error(`arpc doesn't support the type ${t.constructor.name} yet`)}var it=/^(["'`])(.*)\1$/;function _(t){let e=it.exec(t);return e?e[2]:t}function U(t,e){for(let i of Object.values(t)){if(typeof i!="string"){U(i,e);continue}e.has(i)||e.add(i)}}var ot=/^TokenTypes\.([A-Za-z0-9_]+)$/;function rt(t){if(t==="undefined")return;let e=ot.exec(t||"");if(!e)throw new Error(`Invalid token type: ${t}`);return e[1]}async function G(t){let e=(0,b.join)(process.cwd(),"rpc"),i=(0,K.parse)(await(0,j.readFile)((0,b.join)(e,"index.ts"),"utf-8")),a=[(0,b.join)(e,"index.ts")];i.hasAuthentication&&a.push((0,b.join)(e,"authentication.ts")),i.hasRatelimiting&&a.push((0,b.join)(e,"ratelimiting.ts"));let l=new Set;U(i.routes,l),U(i.exceptions,l);for(let s of l)a.push((0,b.join)(e,s));let O=(0,o.createProgram)(a,{allowJs:!0,alwaysStrict:!1});O.getTypeChecker();let d=null;if(i.hasAuthentication){let s=O.getSourceFile((0,b.join)(e,"authentication.ts"));if(!s)throw new Error("Failed to parse rpc/authentication.ts");let r=null,E=null;if(d=s.forEachChild(f=>{if((0,o.isEnumDeclaration)(f)&&f.name.text==="TokenTypes"){r={};for(let p of f.members){let T=_(p.name.getText());if(!p.initializer||!(0,o.isStringLiteral)(p.initializer))throw new Error(`TokenTypes.${T} must be a string literal`);r[T]=_(p.initializer.getText())}return E!==null?{tokenTypes:r,defaultTokenType:E}:void 0}if((0,o.isVariableStatement)(f)){let p=f.declarationList.declarations;if(p.length===1){let T=p[0];if(T.name.getText()==="defaultTokenType"&&(E=rt(T.initializer?.getText()),r))return{tokenTypes:r,defaultTokenType:E}}}})||null,r)d||(d={tokenTypes:r});else throw new Error("Failed to find TokenTypes enum in rpc/authentication.ts")}let m=[],w=Object.keys(i.exceptions).sort();for(let s of w){let r=(0,b.join)(e,i.exceptions[s]+".ts"),E=O.getSourceFile(r);if(!E)throw new Error(`Failed to parse ${r}`);let f=E.forEachChild(y=>{if((0,o.isClassDeclaration)(y)&&y.name?.text===s)return y});if(!f)throw new Error(`Failed to find class ${s} in ${r}`);let p=null,T=f.getFullStart(),Z=f.getStart();if(T!==Z){let y=E.getFullText(),g=(0,o.getLeadingCommentRanges)(y,Z);g&&(p=y.substring(g[0].pos,g[0].end).trim())}m.push({name:s,description:p||`A ${s} custom exception`})}let u=t._routes,h=[],S=[],k=new Set;function z(s,r,E){let f=(u||{})[E],p=null,T=null,Z,y=0;for(;f;){let n=f[r[y]];if(n.input&&n.input instanceof Y.default.ZodType){p=n.input,T=n.output,Z=n.mutation;break}f=n,y++}if(!p||!T)throw new Error("Lockfile and router routes are out of sync");let g=new Map;s.forEachChild(n=>{(0,o.isTypeAliasDeclaration)(n)&&g.set(n.name.text,n.type.getText())});for(let[n,x]of g){for(;g.has(x);)x=g.get(x);g.set(n,x)}let $=s.forEachChild(n=>{if((0,o.isVariableStatement)(n)){let x=n.declarationList.declarations;if(x.length!==1)return;let M=x[0];if(M.name.getText()==="method"){if(M.initializer&&((0,o.isArrowFunction)(M.initializer)||(0,o.isFunctionExpression)(M.initializer)))return M.initializer;throw new Error("method must be an arrow function or function expression")}}if(((0,o.isMethodDeclaration)(n)||(0,o.isFunctionDeclaration)(n))&&n.name?.getText()==="method")return n});if(!$)throw new Error("Failed to find method");let v=$.parameters[0];if(!v)throw new Error("Method must have at least one argument");let C=null;if(v.type){let n=v.type.getText();if(n!=="z.infer<typeof input>"){if(g.get(n)!=="z.infer<typeof input>")throw new Error(`Method argument must be of type or alias a type that is equal to z.infer<typeof input> in the same file, got ${n}`);C=n}}let A={name:v.name.getText(),signature:R(p,h,S,k,()=>C||r.map(n=>n[0].toUpperCase()+n.slice(1)).join("")+"Opts")},H=R(T,h,S,k,()=>r.map(n=>n[0].toUpperCase()+n.slice(1)).join("")+"Response"),V=null,Q=$.getFullStart(),D=$.getStart();if(Q!==D){let n=s.getFullText(),x=(0,o.getLeadingCommentRanges)(n,D);x&&(V=n.substring(x[0].pos,x[0].end).trim())}return Z===void 0&&(Z=!0),{input:A,output:H,description:V,mutation:Z}}let F=Object.keys(i.routes).sort(),L=[];for(let s of F){let p=function(T,Z,y){for(let[g,$]of Object.entries(T)){if(typeof $!="string"){let A={};Z[g]=A,y.push(g),p($,A,y),y.pop();continue}let v=(0,b.join)(e,$+".ts"),C=O.getSourceFile(v);if(!C)throw new Error(`Failed to parse ${v}`);y.push(g),Z[g]=z(C,y,s),y.pop()}};var at=p;let r=null;try{r=await(0,j.readFile)((0,b.join)(e,"descriptions",`${s}.md`),"utf-8")}catch{}r===`You can write markdown here to describe your API version. | ||
`&&(r=null);let E=i.routes[s],f={};L.push({apiVersion:s,methods:f,description:r,defaultProtocol:"",defaultHostname:"",authentication:d}),p(E,f,[])}return{enums:h,objects:S,builtinExceptions:J,customExceptions:m,clients:L}}0&&(module.exports={generateSchema}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@arpc-packages/schema-gen", | ||
"version": "0.2.3", | ||
"version": "0.2.4", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "types": "src/index.ts", |
@@ -8,3 +8,3 @@ import { readFile } from "fs/promises"; | ||
import type { RPCRouter } from "@arpc-packages/core"; | ||
import ts, { | ||
import { | ||
SourceFile, createProgram, getLeadingCommentRanges, isArrowFunction, | ||
@@ -53,11 +53,2 @@ isClassDeclaration, isEnumDeclaration, isFunctionExpression, | ||
function getName(node: any) { | ||
if (!node) return ""; | ||
if (typeof node === "string") return node; | ||
if ("escapedText" in node) { | ||
return node.escapedText; | ||
} | ||
return node.getText(); | ||
} | ||
// Generates a schema using the TypeScript processor and the files on disk. Note that this is VERY | ||
@@ -93,2 +84,5 @@ // slow and partially blocking, so should only be ran during page build in production. | ||
// This shouldn't work, but it does. Force TypeScript to parse the files properly. | ||
tsProgram.getTypeChecker(); | ||
// Handle authentication. | ||
@@ -111,3 +105,3 @@ let authentication: AuthenticationType | null = null; | ||
for (const member of node.members) { | ||
const title = dequotify(getName(member.name)); | ||
const title = dequotify(member.name.getText()); | ||
@@ -118,3 +112,3 @@ // Check the initializer is a string literal. | ||
} | ||
tokenTypes[title] = dequotify(getName(member.initializer)); | ||
tokenTypes[title] = dequotify(member.initializer.getText()); | ||
} | ||
@@ -133,4 +127,4 @@ | ||
const decl = declList[0]; | ||
if (getName(decl.name) === "defaultTokenType") { | ||
defaultTokenType = isTokenType(getName(decl.initializer)); | ||
if (decl.name.getText() === "defaultTokenType") { | ||
defaultTokenType = isTokenType(decl.initializer?.getText()); | ||
if (tokenTypes) { | ||
@@ -240,3 +234,3 @@ return { tokenTypes, defaultTokenType }; | ||
if (isTypeAliasDeclaration(node)) { | ||
typeAliases.set(node.name.text, getName(node.type)); | ||
typeAliases.set(node.name.text, node.type.getText()); | ||
} | ||
@@ -266,3 +260,3 @@ }); | ||
// Check the name. | ||
if (getName(decl.name) === "method") { | ||
if (decl.name.getText() === "method") { | ||
// Check the initializer is a function. | ||
@@ -285,3 +279,3 @@ if ( | ||
// Handle classic methods. | ||
if ((isMethodDeclaration(node) || isFunctionDeclaration(node)) && getName(node.name) === "method") { | ||
if ((isMethodDeclaration(node) || isFunctionDeclaration(node)) && node.name?.getText() === "method") { | ||
return node; | ||
@@ -305,3 +299,3 @@ } | ||
const typeText = getName(arg.type); | ||
const typeText = arg.type.getText(); | ||
if (typeText !== "z.infer<typeof input>") { | ||
@@ -318,3 +312,3 @@ const t = typeAliases.get(typeText); | ||
const input = { | ||
name: getName(arg.name), | ||
name: arg.name.getText(), | ||
signature: getZodSignature( | ||
@@ -321,0 +315,0 @@ inputSchema, enums, objects, uniqueNames, () => inputTypeName || (path.map( |
Sorry, the diff of this file is not supported yet
63328
572