moonflower 1.3.3 → 1.3.5
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/dist/openapi/analyzerModule/nodeParsers.cjs +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.cjs.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.mjs +98 -96
- package/dist/openapi/analyzerModule/nodeParsers.mjs.map +1 -1
- package/dist/openapi/analyzerModule/test/TestCase.d.ts +2 -0
- package/dist/openapi/analyzerModule/test/TestCase.d.ts.map +1 -1
- package/dist/openapi/generatorModule/getSchema.cjs +1 -1
- package/dist/openapi/generatorModule/getSchema.cjs.map +1 -1
- package/dist/openapi/generatorModule/getSchema.d.ts.map +1 -1
- package/dist/openapi/generatorModule/getSchema.mjs +6 -6
- package/dist/openapi/generatorModule/getSchema.mjs.map +1 -1
- package/dist/test/TestAppRouter.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/hooks/useApiEndpoint.spec.ts +2 -0
- package/src/hooks/useApiHeader/useApiHeader.spec.ts +2 -0
- package/src/hooks/useCookieParams.spec.ts +2 -0
- package/src/hooks/useHeaderParams.spec.ts +2 -0
- package/src/hooks/usePathParams.spec.ts +1 -0
- package/src/hooks/useQueryParams.spec.ts +1 -0
- package/src/hooks/useRequestBody.spec.ts +1 -0
- package/src/hooks/useRequestRawBody.spec.ts +2 -0
- package/src/hooks/useReturnValue.spec.ts +2 -0
- package/src/openapi/analyzerModule/nodeParsers.ts +4 -0
- package/src/openapi/analyzerModule/test/TestCase.ts +2 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.ts +9 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.ts +43 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.zod.spec.ts +2 -0
- package/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.ts +1 -0
- package/src/openapi/generatorModule/getSchema.ts +4 -0
- package/src/test/TestAppRouter.ts +8 -0
- package/src/test/app.spec.ts +80 -1
- package/src/utils/object.spec.ts +2 -0
- package/src/utils/printers.spec.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSchema.cjs","sources":["../../../src/openapi/generatorModule/getSchema.ts"],"sourcesContent":["import {\n\tShapeOfNumberLiteral,\n\tShapeOfProperty,\n\tShapeOfRecord,\n\tShapeOfRef,\n\tShapeOfStringLiteral,\n\tShapeOfTuple,\n\tShapeOfType,\n\tShapeOfUnion,\n} from '../../openapi/analyzerModule/types'\nimport { Logger } from '../../utils/logger'\n\nexport type SchemaType =\n\t| { type: string }\n\t| { type: string; properties: Record<string, SchemaType>; required: string[] }\n\t| { oneOf: SchemaType[] }\n\t| { allOf: SchemaType[] }\n\t| { type: 'array'; items: SchemaType }\n\t| { type: 'array'; items: SchemaType; minItems: number; maxItems: number }\n\t| { type: 'object'; additionalProperties: SchemaType }\n\t| { type: 'string'; enum: string[] }\n\t| { type: 'string'; format: string }\n\t| { type: 'number'; enum: string[] }\n\t| { $ref: string }\n\nexport const getSchema = (shape: string | ShapeOfType[]): SchemaType => {\n\tif (typeof shape === 'string' && shape === 'any') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'circular') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'null') {\n\t\treturn {\n\t\t\ttype: 'null',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'Date') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'date-time',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'bigint') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'bigint',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string') {\n\t\treturn {\n\t\t\ttype: shape,\n\t\t}\n\t}\n\n\tif (shape.length === 0) {\n\t\tLogger.warn(`Unknown shape ${shape}`)\n\t\treturn {\n\t\t\ttype: 'unknown_20',\n\t\t}\n\t}\n\n\tconst isStringLiteral = shape[0].role === 'literal_string'\n\tif (isStringLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfStringLiteral\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isNumberLiteral = shape[0].role === 'literal_number'\n\tif (isNumberLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfNumberLiteral\n\t\treturn {\n\t\t\ttype: 'number',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isObject = shape[0].role === 'property'\n\tif (isObject) {\n\t\tconst typedShapes = shape as ShapeOfProperty[]\n\t\tconst properties: Record<string, SchemaType> = {}\n\t\ttypedShapes.forEach((prop) => {\n\t\t\tproperties[prop.identifier] = getSchema(prop.shape)\n\t\t})\n\t\tconst required = typedShapes.filter((prop) => !prop.optional).map((prop) => prop.identifier)\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tproperties,\n\t\t\trequired: required.length > 0 ? required : undefined,\n\t\t}\n\t}\n\n\tconst isUnion = shape[0].role === 'union'\n\tif (isUnion) {\n\t\tconst typedShape = shape[0] as ShapeOfUnion\n\t\treturn {\n\t\t\toneOf: typedShape.shape.map((unionEntry) => getSchema(unionEntry.shape)),\n\t\t}\n\t}\n\n\tconst isRecord = shape[0].role === 'record'\n\tif (isRecord) {\n\t\tconst recordShape = shape[0] as ShapeOfRecord\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tadditionalProperties: getSchema(recordShape.shape),\n\t\t}\n\t}\n\n\tconst isArray = shape[0].role === 'array'\n\tif (isArray) {\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: getSchema(shape[0].shape),\n\t\t}\n\t}\n\n\tconst isRef = shape[0].role === 'ref'\n\tif (isRef) {\n\t\tconst refShape = shape[0] as ShapeOfRef\n\t\treturn {\n\t\t\t$ref: `#/components/schemas/${refShape.shape}`,\n\t\t}\n\t}\n\n\tconst isTuple = shape[0].role === 'tuple'\n\tif (isTuple) {\n\t\tconst tupleShape = shape[0] as ShapeOfTuple\n\t\tconst tupleEntries = tupleShape.shape\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: {\n\t\t\t\toneOf: tupleEntries.map((entry) => getSchema(entry.shape)),\n\t\t\t},\n\t\t\tminItems: tupleEntries.length,\n\t\t\tmaxItems: tupleEntries.length,\n\t\t}\n\t}\n\n\tconst isBuffer = shape[0].role === 'buffer'\n\tif (isBuffer) {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'binary',\n\t\t}\n\t}\n\n\tLogger.warn(`Unknown shape ${shape}`)\n\treturn {\n\t\ttype: 'unknown_21',\n\t}\n}\n\nconst generateAny = () => ({\n\toneOf: [\n\t\t{\n\t\t\ttype: 'string',\n\t\t},\n\t\t{\n\t\t\ttype: 'boolean',\n\t\t},\n\t\t{\n\t\t\ttype: 'number',\n\t\t},\n\t\t{\n\t\t\ttype: 'object',\n\t\t},\n\t\t{\n\t\t\ttype: 'array',\n\t\t},\n\t],\n})\n"],"names":["getSchema","shape","generateAny","Logger","typedShapes","properties","prop","required","unionEntry","recordShape","tupleEntries","entry"],"mappings":"0HAyBaA,EAAaC,GAA8C,
|
|
1
|
+
{"version":3,"file":"getSchema.cjs","sources":["../../../src/openapi/generatorModule/getSchema.ts"],"sourcesContent":["import {\n\tShapeOfNumberLiteral,\n\tShapeOfProperty,\n\tShapeOfRecord,\n\tShapeOfRef,\n\tShapeOfStringLiteral,\n\tShapeOfTuple,\n\tShapeOfType,\n\tShapeOfUnion,\n} from '../../openapi/analyzerModule/types'\nimport { Logger } from '../../utils/logger'\n\nexport type SchemaType =\n\t| { type: string }\n\t| { type: string; properties: Record<string, SchemaType>; required: string[] }\n\t| { oneOf: SchemaType[] }\n\t| { allOf: SchemaType[] }\n\t| { type: 'array'; items: SchemaType }\n\t| { type: 'array'; items: SchemaType; minItems: number; maxItems: number }\n\t| { type: 'object'; additionalProperties: SchemaType }\n\t| { type: 'string'; enum: string[] }\n\t| { type: 'string'; format: string }\n\t| { type: 'number'; enum: string[] }\n\t| { $ref: string }\n\nexport const getSchema = (shape: string | ShapeOfType[]): SchemaType => {\n\tif (typeof shape === 'string' && shape === 'any') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'unknown') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'circular') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'null') {\n\t\treturn {\n\t\t\ttype: 'null',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'Date') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'date-time',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'bigint') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'bigint',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string') {\n\t\treturn {\n\t\t\ttype: shape,\n\t\t}\n\t}\n\n\tif (shape.length === 0) {\n\t\tLogger.warn(`Unknown shape ${shape}`)\n\t\treturn {\n\t\t\ttype: 'unknown_20',\n\t\t}\n\t}\n\n\tconst isStringLiteral = shape[0].role === 'literal_string'\n\tif (isStringLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfStringLiteral\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isNumberLiteral = shape[0].role === 'literal_number'\n\tif (isNumberLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfNumberLiteral\n\t\treturn {\n\t\t\ttype: 'number',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isObject = shape[0].role === 'property'\n\tif (isObject) {\n\t\tconst typedShapes = shape as ShapeOfProperty[]\n\t\tconst properties: Record<string, SchemaType> = {}\n\t\ttypedShapes.forEach((prop) => {\n\t\t\tproperties[prop.identifier] = getSchema(prop.shape)\n\t\t})\n\t\tconst required = typedShapes.filter((prop) => !prop.optional).map((prop) => prop.identifier)\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tproperties,\n\t\t\trequired: required.length > 0 ? required : undefined,\n\t\t}\n\t}\n\n\tconst isUnion = shape[0].role === 'union'\n\tif (isUnion) {\n\t\tconst typedShape = shape[0] as ShapeOfUnion\n\t\treturn {\n\t\t\toneOf: typedShape.shape.map((unionEntry) => getSchema(unionEntry.shape)),\n\t\t}\n\t}\n\n\tconst isRecord = shape[0].role === 'record'\n\tif (isRecord) {\n\t\tconst recordShape = shape[0] as ShapeOfRecord\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tadditionalProperties: getSchema(recordShape.shape),\n\t\t}\n\t}\n\n\tconst isArray = shape[0].role === 'array'\n\tif (isArray) {\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: getSchema(shape[0].shape),\n\t\t}\n\t}\n\n\tconst isRef = shape[0].role === 'ref'\n\tif (isRef) {\n\t\tconst refShape = shape[0] as ShapeOfRef\n\t\treturn {\n\t\t\t$ref: `#/components/schemas/${refShape.shape}`,\n\t\t}\n\t}\n\n\tconst isTuple = shape[0].role === 'tuple'\n\tif (isTuple) {\n\t\tconst tupleShape = shape[0] as ShapeOfTuple\n\t\tconst tupleEntries = tupleShape.shape\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: {\n\t\t\t\toneOf: tupleEntries.map((entry) => getSchema(entry.shape)),\n\t\t\t},\n\t\t\tminItems: tupleEntries.length,\n\t\t\tmaxItems: tupleEntries.length,\n\t\t}\n\t}\n\n\tconst isBuffer = shape[0].role === 'buffer'\n\tif (isBuffer) {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'binary',\n\t\t}\n\t}\n\n\tLogger.warn(`Unknown shape ${shape}`)\n\treturn {\n\t\ttype: 'unknown_21',\n\t}\n}\n\nconst generateAny = () => ({\n\toneOf: [\n\t\t{\n\t\t\ttype: 'string',\n\t\t},\n\t\t{\n\t\t\ttype: 'boolean',\n\t\t},\n\t\t{\n\t\t\ttype: 'number',\n\t\t},\n\t\t{\n\t\t\ttype: 'object',\n\t\t},\n\t\t{\n\t\t\ttype: 'array',\n\t\t},\n\t],\n})\n"],"names":["getSchema","shape","generateAny","Logger","typedShapes","properties","prop","required","unionEntry","recordShape","tupleEntries","entry"],"mappings":"0HAyBaA,EAAaC,GAA8C,CASvE,GARI,OAAOA,GAAU,UAAYA,IAAU,OAIvC,OAAOA,GAAU,UAAYA,IAAU,WAIvC,OAAOA,GAAU,UAAYA,IAAU,WAC1C,OAAOC,EAAY,EAGpB,GAAI,OAAOD,GAAU,UAAYA,IAAU,OACnC,MAAA,CACN,KAAM,MACP,EAGD,GAAI,OAAOA,GAAU,UAAYA,IAAU,OACnC,MAAA,CACN,KAAM,SACN,OAAQ,WACT,EAGD,GAAI,OAAOA,GAAU,UAAYA,IAAU,SACnC,MAAA,CACN,KAAM,SACN,OAAQ,QACT,EAGG,GAAA,OAAOA,GAAU,SACb,MAAA,CACN,KAAMA,CACP,EAGG,GAAAA,EAAM,SAAW,EACbE,OAAAA,EAAAA,OAAA,KAAK,iBAAiBF,CAAK,EAAE,EAC7B,CACN,KAAM,YACP,EAID,GADwBA,EAAM,CAAC,EAAE,OAAS,iBAGlC,MAAA,CACN,KAAM,SACN,KAAM,CAHYA,EAAM,CAAC,EAGP,KAAK,CACxB,EAID,GADwBA,EAAM,CAAC,EAAE,OAAS,iBAGlC,MAAA,CACN,KAAM,SACN,KAAM,CAHYA,EAAM,CAAC,EAGP,KAAK,CACxB,EAID,GADiBA,EAAM,CAAC,EAAE,OAAS,WACrB,CACb,MAAMG,EAAcH,EACdI,EAAyC,CAAC,EACpCD,EAAA,QAASE,GAAS,CAC7BD,EAAWC,EAAK,UAAU,EAAIN,EAAUM,EAAK,KAAK,CAAA,CAClD,EACD,MAAMC,EAAWH,EAAY,OAAQE,GAAS,CAACA,EAAK,QAAQ,EAAE,IAAKA,GAASA,EAAK,UAAU,EACpF,MAAA,CACN,KAAM,SACN,WAAAD,EACA,SAAUE,EAAS,OAAS,EAAIA,EAAW,MAC5C,CAAA,CAID,GADgBN,EAAM,CAAC,EAAE,OAAS,QAG1B,MAAA,CACN,MAFkBA,EAAM,CAAC,EAEP,MAAM,IAAKO,GAAeR,EAAUQ,EAAW,KAAK,CAAC,CACxE,EAID,GADiBP,EAAM,CAAC,EAAE,OAAS,SACrB,CACP,MAAAQ,EAAcR,EAAM,CAAC,EACpB,MAAA,CACN,KAAM,SACN,qBAAsBD,EAAUS,EAAY,KAAK,CAClD,CAAA,CAID,GADgBR,EAAM,CAAC,EAAE,OAAS,QAE1B,MAAA,CACN,KAAM,QACN,MAAOD,EAAUC,EAAM,CAAC,EAAE,KAAK,CAChC,EAID,GADcA,EAAM,CAAC,EAAE,OAAS,MAGxB,MAAA,CACN,KAAM,wBAFUA,EAAM,CAAC,EAEgB,KAAK,EAC7C,EAID,GADgBA,EAAM,CAAC,EAAE,OAAS,QACrB,CAEZ,MAAMS,EADaT,EAAM,CAAC,EACM,MACzB,MAAA,CACN,KAAM,QACN,MAAO,CACN,MAAOS,EAAa,IAAKC,GAAUX,EAAUW,EAAM,KAAK,CAAC,CAC1D,EACA,SAAUD,EAAa,OACvB,SAAUA,EAAa,MACxB,CAAA,CAID,OADiBT,EAAM,CAAC,EAAE,OAAS,SAE3B,CACN,KAAM,SACN,OAAQ,QACT,GAGME,EAAAA,OAAA,KAAK,iBAAiBF,CAAK,EAAE,EAC7B,CACN,KAAM,YACP,EACD,EAEMC,EAAc,KAAO,CAC1B,MAAO,CACN,CACC,KAAM,QACP,EACA,CACC,KAAM,SACP,EACA,CACC,KAAM,QACP,EACA,CACC,KAAM,QACP,EACA,CACC,KAAM,OAAA,CACP,CAEF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSchema.d.ts","sourceRoot":"","sources":["../../../src/openapi/generatorModule/getSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAON,WAAW,EAEX,MAAM,oCAAoC,CAAA;AAG3C,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5E;IAAE,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GACvB;IAAE,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,oBAAoB,EAAE,UAAU,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnB,eAAO,MAAM,SAAS,UAAW,MAAM,GAAG,WAAW,EAAE,KAAG,
|
|
1
|
+
{"version":3,"file":"getSchema.d.ts","sourceRoot":"","sources":["../../../src/openapi/generatorModule/getSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAON,WAAW,EAEX,MAAM,oCAAoC,CAAA;AAG3C,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5E;IAAE,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GACvB;IAAE,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,oBAAoB,EAAE,UAAU,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnB,eAAO,MAAM,SAAS,UAAW,MAAM,GAAG,WAAW,EAAE,KAAG,UA0IzD,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Logger as
|
|
1
|
+
import { Logger as u } from "../../utils/logger.mjs";
|
|
2
2
|
const i = (t) => {
|
|
3
|
-
if (typeof t == "string" && t === "any" || typeof t == "string" && t === "circular")
|
|
4
|
-
return
|
|
3
|
+
if (typeof t == "string" && t === "any" || typeof t == "string" && t === "unknown" || typeof t == "string" && t === "circular")
|
|
4
|
+
return f();
|
|
5
5
|
if (typeof t == "string" && t === "null")
|
|
6
6
|
return {
|
|
7
7
|
type: "null"
|
|
@@ -21,7 +21,7 @@ const i = (t) => {
|
|
|
21
21
|
type: t
|
|
22
22
|
};
|
|
23
23
|
if (t.length === 0)
|
|
24
|
-
return
|
|
24
|
+
return u.warn(`Unknown shape ${t}`), {
|
|
25
25
|
type: "unknown_20"
|
|
26
26
|
};
|
|
27
27
|
if (t[0].role === "literal_string")
|
|
@@ -80,10 +80,10 @@ const i = (t) => {
|
|
|
80
80
|
return t[0].role === "buffer" ? {
|
|
81
81
|
type: "string",
|
|
82
82
|
format: "binary"
|
|
83
|
-
} : (
|
|
83
|
+
} : (u.warn(`Unknown shape ${t}`), {
|
|
84
84
|
type: "unknown_21"
|
|
85
85
|
});
|
|
86
|
-
},
|
|
86
|
+
}, f = () => ({
|
|
87
87
|
oneOf: [
|
|
88
88
|
{
|
|
89
89
|
type: "string"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSchema.mjs","sources":["../../../src/openapi/generatorModule/getSchema.ts"],"sourcesContent":["import {\n\tShapeOfNumberLiteral,\n\tShapeOfProperty,\n\tShapeOfRecord,\n\tShapeOfRef,\n\tShapeOfStringLiteral,\n\tShapeOfTuple,\n\tShapeOfType,\n\tShapeOfUnion,\n} from '../../openapi/analyzerModule/types'\nimport { Logger } from '../../utils/logger'\n\nexport type SchemaType =\n\t| { type: string }\n\t| { type: string; properties: Record<string, SchemaType>; required: string[] }\n\t| { oneOf: SchemaType[] }\n\t| { allOf: SchemaType[] }\n\t| { type: 'array'; items: SchemaType }\n\t| { type: 'array'; items: SchemaType; minItems: number; maxItems: number }\n\t| { type: 'object'; additionalProperties: SchemaType }\n\t| { type: 'string'; enum: string[] }\n\t| { type: 'string'; format: string }\n\t| { type: 'number'; enum: string[] }\n\t| { $ref: string }\n\nexport const getSchema = (shape: string | ShapeOfType[]): SchemaType => {\n\tif (typeof shape === 'string' && shape === 'any') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'circular') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'null') {\n\t\treturn {\n\t\t\ttype: 'null',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'Date') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'date-time',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'bigint') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'bigint',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string') {\n\t\treturn {\n\t\t\ttype: shape,\n\t\t}\n\t}\n\n\tif (shape.length === 0) {\n\t\tLogger.warn(`Unknown shape ${shape}`)\n\t\treturn {\n\t\t\ttype: 'unknown_20',\n\t\t}\n\t}\n\n\tconst isStringLiteral = shape[0].role === 'literal_string'\n\tif (isStringLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfStringLiteral\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isNumberLiteral = shape[0].role === 'literal_number'\n\tif (isNumberLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfNumberLiteral\n\t\treturn {\n\t\t\ttype: 'number',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isObject = shape[0].role === 'property'\n\tif (isObject) {\n\t\tconst typedShapes = shape as ShapeOfProperty[]\n\t\tconst properties: Record<string, SchemaType> = {}\n\t\ttypedShapes.forEach((prop) => {\n\t\t\tproperties[prop.identifier] = getSchema(prop.shape)\n\t\t})\n\t\tconst required = typedShapes.filter((prop) => !prop.optional).map((prop) => prop.identifier)\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tproperties,\n\t\t\trequired: required.length > 0 ? required : undefined,\n\t\t}\n\t}\n\n\tconst isUnion = shape[0].role === 'union'\n\tif (isUnion) {\n\t\tconst typedShape = shape[0] as ShapeOfUnion\n\t\treturn {\n\t\t\toneOf: typedShape.shape.map((unionEntry) => getSchema(unionEntry.shape)),\n\t\t}\n\t}\n\n\tconst isRecord = shape[0].role === 'record'\n\tif (isRecord) {\n\t\tconst recordShape = shape[0] as ShapeOfRecord\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tadditionalProperties: getSchema(recordShape.shape),\n\t\t}\n\t}\n\n\tconst isArray = shape[0].role === 'array'\n\tif (isArray) {\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: getSchema(shape[0].shape),\n\t\t}\n\t}\n\n\tconst isRef = shape[0].role === 'ref'\n\tif (isRef) {\n\t\tconst refShape = shape[0] as ShapeOfRef\n\t\treturn {\n\t\t\t$ref: `#/components/schemas/${refShape.shape}`,\n\t\t}\n\t}\n\n\tconst isTuple = shape[0].role === 'tuple'\n\tif (isTuple) {\n\t\tconst tupleShape = shape[0] as ShapeOfTuple\n\t\tconst tupleEntries = tupleShape.shape\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: {\n\t\t\t\toneOf: tupleEntries.map((entry) => getSchema(entry.shape)),\n\t\t\t},\n\t\t\tminItems: tupleEntries.length,\n\t\t\tmaxItems: tupleEntries.length,\n\t\t}\n\t}\n\n\tconst isBuffer = shape[0].role === 'buffer'\n\tif (isBuffer) {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'binary',\n\t\t}\n\t}\n\n\tLogger.warn(`Unknown shape ${shape}`)\n\treturn {\n\t\ttype: 'unknown_21',\n\t}\n}\n\nconst generateAny = () => ({\n\toneOf: [\n\t\t{\n\t\t\ttype: 'string',\n\t\t},\n\t\t{\n\t\t\ttype: 'boolean',\n\t\t},\n\t\t{\n\t\t\ttype: 'number',\n\t\t},\n\t\t{\n\t\t\ttype: 'object',\n\t\t},\n\t\t{\n\t\t\ttype: 'array',\n\t\t},\n\t],\n})\n"],"names":["getSchema","shape","generateAny","Logger","typedShapes","properties","prop","required","unionEntry","recordShape","tupleEntries","entry"],"mappings":";AAyBa,MAAAA,IAAY,CAACC,MAA8C;
|
|
1
|
+
{"version":3,"file":"getSchema.mjs","sources":["../../../src/openapi/generatorModule/getSchema.ts"],"sourcesContent":["import {\n\tShapeOfNumberLiteral,\n\tShapeOfProperty,\n\tShapeOfRecord,\n\tShapeOfRef,\n\tShapeOfStringLiteral,\n\tShapeOfTuple,\n\tShapeOfType,\n\tShapeOfUnion,\n} from '../../openapi/analyzerModule/types'\nimport { Logger } from '../../utils/logger'\n\nexport type SchemaType =\n\t| { type: string }\n\t| { type: string; properties: Record<string, SchemaType>; required: string[] }\n\t| { oneOf: SchemaType[] }\n\t| { allOf: SchemaType[] }\n\t| { type: 'array'; items: SchemaType }\n\t| { type: 'array'; items: SchemaType; minItems: number; maxItems: number }\n\t| { type: 'object'; additionalProperties: SchemaType }\n\t| { type: 'string'; enum: string[] }\n\t| { type: 'string'; format: string }\n\t| { type: 'number'; enum: string[] }\n\t| { $ref: string }\n\nexport const getSchema = (shape: string | ShapeOfType[]): SchemaType => {\n\tif (typeof shape === 'string' && shape === 'any') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'unknown') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'circular') {\n\t\treturn generateAny()\n\t}\n\n\tif (typeof shape === 'string' && shape === 'null') {\n\t\treturn {\n\t\t\ttype: 'null',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'Date') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'date-time',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string' && shape === 'bigint') {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'bigint',\n\t\t}\n\t}\n\n\tif (typeof shape === 'string') {\n\t\treturn {\n\t\t\ttype: shape,\n\t\t}\n\t}\n\n\tif (shape.length === 0) {\n\t\tLogger.warn(`Unknown shape ${shape}`)\n\t\treturn {\n\t\t\ttype: 'unknown_20',\n\t\t}\n\t}\n\n\tconst isStringLiteral = shape[0].role === 'literal_string'\n\tif (isStringLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfStringLiteral\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isNumberLiteral = shape[0].role === 'literal_number'\n\tif (isNumberLiteral) {\n\t\tconst typedShape = shape[0] as ShapeOfNumberLiteral\n\t\treturn {\n\t\t\ttype: 'number',\n\t\t\tenum: [typedShape.shape],\n\t\t}\n\t}\n\n\tconst isObject = shape[0].role === 'property'\n\tif (isObject) {\n\t\tconst typedShapes = shape as ShapeOfProperty[]\n\t\tconst properties: Record<string, SchemaType> = {}\n\t\ttypedShapes.forEach((prop) => {\n\t\t\tproperties[prop.identifier] = getSchema(prop.shape)\n\t\t})\n\t\tconst required = typedShapes.filter((prop) => !prop.optional).map((prop) => prop.identifier)\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tproperties,\n\t\t\trequired: required.length > 0 ? required : undefined,\n\t\t}\n\t}\n\n\tconst isUnion = shape[0].role === 'union'\n\tif (isUnion) {\n\t\tconst typedShape = shape[0] as ShapeOfUnion\n\t\treturn {\n\t\t\toneOf: typedShape.shape.map((unionEntry) => getSchema(unionEntry.shape)),\n\t\t}\n\t}\n\n\tconst isRecord = shape[0].role === 'record'\n\tif (isRecord) {\n\t\tconst recordShape = shape[0] as ShapeOfRecord\n\t\treturn {\n\t\t\ttype: 'object',\n\t\t\tadditionalProperties: getSchema(recordShape.shape),\n\t\t}\n\t}\n\n\tconst isArray = shape[0].role === 'array'\n\tif (isArray) {\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: getSchema(shape[0].shape),\n\t\t}\n\t}\n\n\tconst isRef = shape[0].role === 'ref'\n\tif (isRef) {\n\t\tconst refShape = shape[0] as ShapeOfRef\n\t\treturn {\n\t\t\t$ref: `#/components/schemas/${refShape.shape}`,\n\t\t}\n\t}\n\n\tconst isTuple = shape[0].role === 'tuple'\n\tif (isTuple) {\n\t\tconst tupleShape = shape[0] as ShapeOfTuple\n\t\tconst tupleEntries = tupleShape.shape\n\t\treturn {\n\t\t\ttype: 'array',\n\t\t\titems: {\n\t\t\t\toneOf: tupleEntries.map((entry) => getSchema(entry.shape)),\n\t\t\t},\n\t\t\tminItems: tupleEntries.length,\n\t\t\tmaxItems: tupleEntries.length,\n\t\t}\n\t}\n\n\tconst isBuffer = shape[0].role === 'buffer'\n\tif (isBuffer) {\n\t\treturn {\n\t\t\ttype: 'string',\n\t\t\tformat: 'binary',\n\t\t}\n\t}\n\n\tLogger.warn(`Unknown shape ${shape}`)\n\treturn {\n\t\ttype: 'unknown_21',\n\t}\n}\n\nconst generateAny = () => ({\n\toneOf: [\n\t\t{\n\t\t\ttype: 'string',\n\t\t},\n\t\t{\n\t\t\ttype: 'boolean',\n\t\t},\n\t\t{\n\t\t\ttype: 'number',\n\t\t},\n\t\t{\n\t\t\ttype: 'object',\n\t\t},\n\t\t{\n\t\t\ttype: 'array',\n\t\t},\n\t],\n})\n"],"names":["getSchema","shape","generateAny","Logger","typedShapes","properties","prop","required","unionEntry","recordShape","tupleEntries","entry"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestAppRouter.d.ts","sourceRoot":"","sources":["../../src/test/TestAppRouter.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"TestAppRouter.d.ts","sourceRoot":"","sources":["../../src/test/TestAppRouter.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAoF1D,eAAO,MAAM,aAAa;;;;EAAW,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moonflower",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "tenebrie",
|
|
6
6
|
"license": "MIT",
|
|
@@ -129,9 +129,13 @@
|
|
|
129
129
|
"@koa/router": "^13.1.0",
|
|
130
130
|
"koa": "^2.15.3",
|
|
131
131
|
"koa-bodyparser": "^4.4.1",
|
|
132
|
+
"ts-morph": "^24.0.0",
|
|
132
133
|
"zod": "4.3.6"
|
|
133
134
|
},
|
|
134
135
|
"peerDependenciesMeta": {
|
|
136
|
+
"ts-morph": {
|
|
137
|
+
"optional": true
|
|
138
|
+
},
|
|
135
139
|
"zod": {
|
|
136
140
|
"optional": true
|
|
137
141
|
}
|
|
@@ -5,4 +5,6 @@ export const TestCase = {
|
|
|
5
5
|
parsesInlineZodNumberArray: 'parses-inline-zod-number-array',
|
|
6
6
|
parsesInlineZodObjectArray: 'parses-inline-zod-object-array',
|
|
7
7
|
parsedAliasedZodSchema: 'parses-aliased-zod-schema',
|
|
8
|
+
parsesReturnRecordStringUnknown: 'parses-return-record-string-unknown',
|
|
9
|
+
parsesReturnObjectWithRecordProperty: 'parses-return-object-with-record-property',
|
|
8
10
|
} as const
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
StringValidator,
|
|
18
18
|
} from '../../../validators/BuiltInValidators'
|
|
19
19
|
import { OptionalParam, PathParam, RequiredParam } from '../../../validators/ParamWrappers'
|
|
20
|
+
import { TestCase } from './TestCase'
|
|
20
21
|
|
|
21
22
|
const router = new Router()
|
|
22
23
|
|
|
@@ -551,6 +552,14 @@ router.get('/test/2ec01787-13d0-4512-9cf3-468f409508b7', () => {
|
|
|
551
552
|
}
|
|
552
553
|
})
|
|
553
554
|
|
|
555
|
+
router.get(`/test/${TestCase.parsesReturnRecordStringUnknown}`, () => {
|
|
556
|
+
return {} as Record<string, unknown>
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
router.get(`/test/${TestCase.parsesReturnObjectWithRecordProperty}`, () => {
|
|
560
|
+
return {} as { foo: string; bar: Record<string, unknown> }
|
|
561
|
+
})
|
|
562
|
+
|
|
554
563
|
// Mimics Prisma's JsonValue / JsonObject: an object with an index signature and no own properties
|
|
555
564
|
type JsonValue = string | number | boolean | JsonObject | JsonArray | null
|
|
556
565
|
type JsonObject = { [Key in string]?: JsonValue }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Project, SyntaxKind } from 'ts-morph'
|
|
2
|
+
import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest'
|
|
2
3
|
|
|
3
4
|
import { loadTestData } from '../../../utils/loadTestData'
|
|
4
5
|
import { StringValidator } from '../../../validators/BuiltInValidators'
|
|
@@ -6,6 +7,7 @@ import { discoverRouters } from '../../discoveryModule/discoverRouters/discoverR
|
|
|
6
7
|
import { OpenApiManager } from '../../manager/OpenApiManager'
|
|
7
8
|
import { analyzeSourceFileEndpoints } from '../analyzerModule'
|
|
8
9
|
import { getValidatorPropertyShape, getValidatorPropertyStringValue } from '../nodeParsers'
|
|
10
|
+
import { TestCase } from './TestCase'
|
|
9
11
|
|
|
10
12
|
describe('OpenApi Analyzer', () => {
|
|
11
13
|
describe('when analyzing a test data file', () => {
|
|
@@ -725,6 +727,47 @@ describe('OpenApi Analyzer', () => {
|
|
|
725
727
|
expect(endpoint.responses.length).toEqual(1)
|
|
726
728
|
})
|
|
727
729
|
|
|
730
|
+
it('parses return Record<string, unknown> type correctly', () => {
|
|
731
|
+
const endpoint = analyzeEndpointById(TestCase.parsesReturnRecordStringUnknown)
|
|
732
|
+
|
|
733
|
+
expect(endpoint.responses[0].status).toEqual(200)
|
|
734
|
+
expect(endpoint.responses[0].signature).toEqual([
|
|
735
|
+
{
|
|
736
|
+
role: 'record',
|
|
737
|
+
shape: 'unknown',
|
|
738
|
+
optional: false,
|
|
739
|
+
},
|
|
740
|
+
])
|
|
741
|
+
expect(endpoint.responses.length).toEqual(1)
|
|
742
|
+
})
|
|
743
|
+
|
|
744
|
+
it('parses return object with Record<string, unknown> property correctly', () => {
|
|
745
|
+
const endpoint = analyzeEndpointById(TestCase.parsesReturnObjectWithRecordProperty)
|
|
746
|
+
|
|
747
|
+
expect(endpoint.responses[0].status).toEqual(200)
|
|
748
|
+
expect(endpoint.responses[0].signature).toEqual([
|
|
749
|
+
{
|
|
750
|
+
role: 'property',
|
|
751
|
+
identifier: 'foo',
|
|
752
|
+
shape: 'string',
|
|
753
|
+
optional: false,
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
role: 'property',
|
|
757
|
+
identifier: 'bar',
|
|
758
|
+
shape: [
|
|
759
|
+
{
|
|
760
|
+
role: 'record',
|
|
761
|
+
shape: 'unknown',
|
|
762
|
+
optional: false,
|
|
763
|
+
},
|
|
764
|
+
],
|
|
765
|
+
optional: false,
|
|
766
|
+
},
|
|
767
|
+
])
|
|
768
|
+
expect(endpoint.responses.length).toEqual(1)
|
|
769
|
+
})
|
|
770
|
+
|
|
728
771
|
it('parses return type with index signature object (like Prisma JsonObject) correctly', () => {
|
|
729
772
|
const endpoint = analyzeEndpointById('c4a1e7b2-9f3d-4e8a-b5c6-7d2f1a3e4b5c')
|
|
730
773
|
|
|
@@ -28,6 +28,10 @@ export const getSchema = (shape: string | ShapeOfType[]): SchemaType => {
|
|
|
28
28
|
return generateAny()
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
if (typeof shape === 'string' && shape === 'unknown') {
|
|
32
|
+
return generateAny()
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
if (typeof shape === 'string' && shape === 'circular') {
|
|
32
36
|
return generateAny()
|
|
33
37
|
}
|
|
@@ -82,4 +82,12 @@ myRouter.get('/test/get/middleware-data', (ctx) => {
|
|
|
82
82
|
}
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
+
myRouter.get('/test/get/record-string-unknown', () => {
|
|
86
|
+
return {} as Record<string, unknown>
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
myRouter.get('/test/get/object-with-record', () => {
|
|
90
|
+
return {} as { foo: string; bar: Record<string, unknown> }
|
|
91
|
+
})
|
|
92
|
+
|
|
85
93
|
export const TestAppRouter = myRouter
|
package/src/test/app.spec.ts
CHANGED
|
@@ -3,7 +3,7 @@ import Koa from 'koa'
|
|
|
3
3
|
import * as os from 'os'
|
|
4
4
|
import * as path from 'path'
|
|
5
5
|
import request from 'supertest'
|
|
6
|
-
import { vi } from 'vitest'
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
7
7
|
|
|
8
8
|
import { generateOpenApiSpec } from '../openapi/generatorModule/generatorModule'
|
|
9
9
|
import { initOpenApiEngine } from '../openapi/initOpenApiEngine'
|
|
@@ -155,6 +155,85 @@ describe('OpenApiRouter', () => {
|
|
|
155
155
|
})
|
|
156
156
|
})
|
|
157
157
|
|
|
158
|
+
it('generates correct spec for Record<string, unknown> return type', async () => {
|
|
159
|
+
const response = await request(app.callback()).get('/api-json')
|
|
160
|
+
const responseJson = JSON.parse(response.text) as ReturnType<typeof generateOpenApiSpec>
|
|
161
|
+
expect(responseJson.paths['/test/get/record-string-unknown']).toEqual({
|
|
162
|
+
get: {
|
|
163
|
+
description: '',
|
|
164
|
+
parameters: [],
|
|
165
|
+
responses: {
|
|
166
|
+
'200': {
|
|
167
|
+
description: '',
|
|
168
|
+
content: {
|
|
169
|
+
'application/json': {
|
|
170
|
+
schema: {
|
|
171
|
+
oneOf: [
|
|
172
|
+
{
|
|
173
|
+
type: 'object',
|
|
174
|
+
additionalProperties: {
|
|
175
|
+
oneOf: [
|
|
176
|
+
{ type: 'string' },
|
|
177
|
+
{ type: 'boolean' },
|
|
178
|
+
{ type: 'number' },
|
|
179
|
+
{ type: 'object' },
|
|
180
|
+
{ type: 'array' },
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('generates correct spec for object with Record<string, unknown> property', async () => {
|
|
195
|
+
const response = await request(app.callback()).get('/api-json')
|
|
196
|
+
const responseJson = JSON.parse(response.text) as ReturnType<typeof generateOpenApiSpec>
|
|
197
|
+
expect(responseJson.paths['/test/get/object-with-record']).toEqual({
|
|
198
|
+
get: {
|
|
199
|
+
description: '',
|
|
200
|
+
parameters: [],
|
|
201
|
+
responses: {
|
|
202
|
+
'200': {
|
|
203
|
+
description: '',
|
|
204
|
+
content: {
|
|
205
|
+
'application/json': {
|
|
206
|
+
schema: {
|
|
207
|
+
oneOf: [
|
|
208
|
+
{
|
|
209
|
+
type: 'object',
|
|
210
|
+
properties: {
|
|
211
|
+
foo: { type: 'string' },
|
|
212
|
+
bar: {
|
|
213
|
+
type: 'object',
|
|
214
|
+
additionalProperties: {
|
|
215
|
+
oneOf: [
|
|
216
|
+
{ type: 'string' },
|
|
217
|
+
{ type: 'boolean' },
|
|
218
|
+
{ type: 'number' },
|
|
219
|
+
{ type: 'object' },
|
|
220
|
+
{ type: 'array' },
|
|
221
|
+
],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
required: ['foo', 'bar'],
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
})
|
|
235
|
+
})
|
|
236
|
+
|
|
158
237
|
it('serves a prebuilt spec from file', async () => {
|
|
159
238
|
const manager = OpenApiManager.getInstance()
|
|
160
239
|
const liveSpec = generateOpenApiSpec(manager)
|
package/src/utils/object.spec.ts
CHANGED