adorn-api 1.0.7 → 1.0.9

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/cli.js CHANGED
@@ -197,7 +197,8 @@ function classifyParameters(parameters, httpMethod, pathParamIndices, checker) {
197
197
  for (let i = 0; i < parameters.length; i++) {
198
198
  const param = parameters[i];
199
199
  if (usedIndices.has(i)) continue;
200
- const typeStr = param.type.getSymbol()?.getName() ?? "";
200
+ const nonNullableType = checker.getNonNullableType(param.type);
201
+ const typeStr = getTypeName(param.type) || getTypeName(nonNullableType);
201
202
  if (typeStr === "Body") {
202
203
  bodyParamIndex = i;
203
204
  usedIndices.add(i);
@@ -223,7 +224,7 @@ function classifyParameters(parameters, httpMethod, pathParamIndices, checker) {
223
224
  usedIndices.add(i);
224
225
  continue;
225
226
  }
226
- const isObj = isObjectType(param.type, checker);
227
+ const isObj = isObjectType(nonNullableType, checker);
227
228
  if (isObj && queryObjectParamIndex === null && !isBodyMethod) {
228
229
  queryObjectParamIndex = i;
229
230
  usedIndices.add(i);
@@ -252,6 +253,12 @@ function isObjectType(type, checker) {
252
253
  if (callSignatures && callSignatures.length > 0) return false;
253
254
  return true;
254
255
  }
256
+ function getTypeName(type) {
257
+ const aliasSymbol = type.aliasSymbol ?? type.aliasSymbol;
258
+ if (aliasSymbol) return aliasSymbol.getName();
259
+ const symbol = type.getSymbol();
260
+ return symbol?.getName() ?? "";
261
+ }
255
262
  function findDecorator(node, name) {
256
263
  const decorators = ts2.getDecorators(node);
257
264
  if (!decorators) return null;
@@ -286,7 +293,7 @@ function unwrapPromise(type, checker) {
286
293
  }
287
294
 
288
295
  // src/compiler/schema/openapi.ts
289
- import ts5 from "typescript";
296
+ import ts6 from "typescript";
290
297
 
291
298
  // src/compiler/schema/typeToJsonSchema.ts
292
299
  import ts3 from "typescript";
@@ -760,6 +767,56 @@ function mergeFragments(base, ...frags) {
760
767
  return result;
761
768
  }
762
769
 
770
+ // src/compiler/analyze/extractQueryStyle.ts
771
+ import ts5 from "typescript";
772
+ function extractQueryStyleOptions(checker, method) {
773
+ if (!ts5.canHaveDecorators(method)) return null;
774
+ const decorators = ts5.getDecorators(method);
775
+ if (!decorators || decorators.length === 0) return null;
776
+ for (const decorator of decorators) {
777
+ const expr = decorator.expression;
778
+ const isCall = ts5.isCallExpression(expr);
779
+ const callee = isCall ? expr.expression : expr;
780
+ const args = isCall ? expr.arguments : ts5.factory.createNodeArray([]);
781
+ const sym = checker.getSymbolAtLocation(callee);
782
+ if (!sym) continue;
783
+ const resolved = sym.flags & ts5.SymbolFlags.Alias ? checker.getAliasedSymbol(sym) : sym;
784
+ const name = resolved.getName();
785
+ if (name !== "QueryStyle") continue;
786
+ const optsNode = args[0];
787
+ if (!optsNode || !ts5.isObjectLiteralExpression(optsNode)) {
788
+ return {};
789
+ }
790
+ return parseQueryStyleOptions(optsNode);
791
+ }
792
+ return null;
793
+ }
794
+ function parseQueryStyleOptions(node) {
795
+ const opts = {};
796
+ for (const prop of node.properties) {
797
+ if (!ts5.isPropertyAssignment(prop)) continue;
798
+ const name = getPropName(prop.name);
799
+ if (!name) continue;
800
+ if (name === "style" && ts5.isStringLiteral(prop.initializer)) {
801
+ const style = prop.initializer.text;
802
+ opts.style = style;
803
+ } else if (name === "explode" && isBooleanLiteral(prop.initializer)) {
804
+ opts.explode = prop.initializer.kind === ts5.SyntaxKind.TrueKeyword;
805
+ } else if (name === "allowReserved" && isBooleanLiteral(prop.initializer)) {
806
+ opts.allowReserved = prop.initializer.kind === ts5.SyntaxKind.TrueKeyword;
807
+ }
808
+ }
809
+ return opts;
810
+ }
811
+ function getPropName(name) {
812
+ if (ts5.isIdentifier(name)) return name.text;
813
+ if (ts5.isStringLiteral(name)) return name.text;
814
+ return null;
815
+ }
816
+ function isBooleanLiteral(node) {
817
+ return node.kind === ts5.SyntaxKind.TrueKeyword || node.kind === ts5.SyntaxKind.FalseKeyword;
818
+ }
819
+
763
820
  // src/compiler/schema/openapi.ts
764
821
  function generateOpenAPI(controllers, checker, options = {}) {
765
822
  const components = /* @__PURE__ */ new Map();
@@ -851,12 +908,12 @@ function mergeBodySchemaAnnotations(bodyParam, ctx, schema) {
851
908
  const declarations = typeSymbol.getDeclarations();
852
909
  if (!declarations || declarations.length === 0) return schema;
853
910
  const classDecl = declarations[0];
854
- if (!ts5.isClassDeclaration(classDecl)) return schema;
911
+ if (!ts6.isClassDeclaration(classDecl)) return schema;
855
912
  const result = { ...schema };
856
913
  const props = { ...result.properties };
857
914
  for (const member of classDecl.members) {
858
- if (!ts5.isPropertyDeclaration(member) || !member.name) continue;
859
- const propName = ts5.isIdentifier(member.name) ? member.name.text : null;
915
+ if (!ts6.isPropertyDeclaration(member) || !member.name) continue;
916
+ const propName = ts6.isIdentifier(member.name) ? member.name.text : null;
860
917
  if (!propName) continue;
861
918
  if (!props[propName]) continue;
862
919
  const frags = extractPropertySchemaFragments(ctx.checker, member);
@@ -891,19 +948,36 @@ function buildQueryParameters(operation, ctx, parameters) {
891
948
  if (operation.queryObjectParamIndex !== null) {
892
949
  const queryParam = operation.parameters[operation.queryObjectParamIndex];
893
950
  if (!queryParam) return;
951
+ const queryStyle = extractQueryStyleOptions(ctx.checker, operation.methodDeclaration);
894
952
  const querySchema = typeToJsonSchema(queryParam.type, ctx);
895
- if (!querySchema.properties) return;
896
- const queryObjProps = querySchema.properties;
897
- for (const [propName, propSchema] of Object.entries(queryObjProps)) {
898
- const isRequired = querySchema.required?.includes(propName) ?? false;
899
- const serialization = determineQuerySerialization(propSchema.type);
900
- parameters.push({
901
- name: propName,
953
+ if (queryStyle?.style === "deepObject") {
954
+ const explode = queryStyle.explode ?? true;
955
+ const deepParam = {
956
+ name: queryParam.name,
902
957
  in: "query",
903
- required: isRequired,
904
- schema: propSchema,
905
- ...Object.keys(serialization).length > 0 ? serialization : {}
906
- });
958
+ required: !queryParam.isOptional,
959
+ schema: querySchema.$ref ? { $ref: querySchema.$ref } : querySchema,
960
+ style: "deepObject",
961
+ explode
962
+ };
963
+ if (queryStyle.allowReserved !== void 0) {
964
+ deepParam.allowReserved = queryStyle.allowReserved;
965
+ }
966
+ parameters.push(deepParam);
967
+ } else {
968
+ if (!querySchema.properties) return;
969
+ const queryObjProps = querySchema.properties;
970
+ for (const [propName, propSchema] of Object.entries(queryObjProps)) {
971
+ const isRequired = querySchema.required?.includes(propName) ?? false;
972
+ const serialization = determineQuerySerialization(propSchema.type);
973
+ parameters.push({
974
+ name: propName,
975
+ in: "query",
976
+ required: isRequired,
977
+ schema: propSchema,
978
+ ...Object.keys(serialization).length > 0 ? serialization : {}
979
+ });
980
+ }
907
981
  }
908
982
  }
909
983
  for (const paramIndex of operation.queryParamIndices) {
@@ -973,7 +1047,7 @@ function buildCookieParameters(operation, ctx, parameters) {
973
1047
  }
974
1048
 
975
1049
  // src/compiler/manifest/emit.ts
976
- import ts6 from "typescript";
1050
+ import ts7 from "typescript";
977
1051
  function generateManifest(controllers, checker, version, validationMode = "ajv-runtime") {
978
1052
  const components = /* @__PURE__ */ new Map();
979
1053
  const ctx = {
@@ -994,7 +1068,7 @@ function generateManifest(controllers, checker, version, validationMode = "ajv-r
994
1068
  generator: {
995
1069
  name: "adorn-api",
996
1070
  version,
997
- typescript: ts6.version
1071
+ typescript: ts7.version
998
1072
  },
999
1073
  schemas: {
1000
1074
  kind: "openapi-3.1",
@@ -1079,21 +1153,38 @@ function buildQueryArgs(op, ctx, args) {
1079
1153
  if (op.queryObjectParamIndex !== null) {
1080
1154
  const queryParam = op.parameters[op.queryObjectParamIndex];
1081
1155
  if (queryParam) {
1156
+ const queryStyle = extractQueryStyleOptions(ctx.checker, op.methodDeclaration);
1082
1157
  const querySchema = typeToJsonSchema(queryParam.type, ctx);
1083
- if (!querySchema.properties) return;
1084
- for (const [propName, propSchema] of Object.entries(querySchema.properties)) {
1085
- const isRequired = querySchema.required?.includes(propName) ?? false;
1086
- let schemaRef = propSchema.$ref;
1087
- if (!schemaRef) {
1088
- schemaRef = "#/components/schemas/InlineQueryParam";
1089
- }
1158
+ if (queryStyle?.style === "deepObject") {
1159
+ const schemaRef = querySchema.$ref ?? "#/components/schemas/InlineQueryParam";
1090
1160
  args.query.push({
1091
- name: propName,
1161
+ name: queryParam.name,
1092
1162
  index: queryParam.index,
1093
- required: !isRequired,
1163
+ required: !queryParam.isOptional,
1094
1164
  schemaRef,
1095
- schemaType: propSchema.type
1165
+ schemaType: querySchema.type,
1166
+ serialization: {
1167
+ style: "deepObject",
1168
+ explode: queryStyle.explode ?? true,
1169
+ allowReserved: queryStyle.allowReserved
1170
+ }
1096
1171
  });
1172
+ } else {
1173
+ if (!querySchema.properties) return;
1174
+ for (const [propName, propSchema] of Object.entries(querySchema.properties)) {
1175
+ const isRequired = querySchema.required?.includes(propName) ?? false;
1176
+ let schemaRef = propSchema.$ref;
1177
+ if (!schemaRef) {
1178
+ schemaRef = "#/components/schemas/InlineQueryParam";
1179
+ }
1180
+ args.query.push({
1181
+ name: propName,
1182
+ index: queryParam.index,
1183
+ required: !isRequired,
1184
+ schemaRef,
1185
+ schemaType: propSchema.type
1186
+ });
1187
+ }
1097
1188
  }
1098
1189
  }
1099
1190
  }
@@ -1402,7 +1493,7 @@ async function isStale(params) {
1402
1493
  // src/compiler/cache/writeCache.ts
1403
1494
  import fs3 from "fs";
1404
1495
  import path3 from "path";
1405
- import ts8 from "typescript";
1496
+ import ts9 from "typescript";
1406
1497
  function statMtimeMs2(p) {
1407
1498
  return fs3.statSync(p).mtimeMs;
1408
1499
  }
@@ -1435,7 +1526,7 @@ function writeCache(params) {
1435
1526
  generator: {
1436
1527
  name: "adorn-api",
1437
1528
  version: params.adornVersion,
1438
- typescript: ts8.version
1529
+ typescript: ts9.version
1439
1530
  },
1440
1531
  project: {
1441
1532
  tsconfigPath: params.tsconfigAbs,
@@ -1448,7 +1539,7 @@ function writeCache(params) {
1448
1539
  }
1449
1540
 
1450
1541
  // src/cli.ts
1451
- import ts9 from "typescript";
1542
+ import ts10 from "typescript";
1452
1543
  import process from "process";
1453
1544
  var ADORN_VERSION = "0.1.0";
1454
1545
  function log(msg) {
@@ -1476,7 +1567,7 @@ async function buildCommand(args) {
1476
1567
  outDir: outputDir,
1477
1568
  project: projectPath,
1478
1569
  adornVersion: ADORN_VERSION,
1479
- typescriptVersion: ts9.version
1570
+ typescriptVersion: ts10.version
1480
1571
  });
1481
1572
  if (!stale.stale) {
1482
1573
  log("adorn-api: artifacts up-to-date");