@nestia/core 13.0.4 → 14.0.1

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.
Files changed (98) hide show
  1. package/MIGRATION.md +20 -0
  2. package/README.md +1 -1
  3. package/lib/adaptors/McpAdaptor.d.ts +5 -0
  4. package/lib/adaptors/McpAdaptor.js +114 -26
  5. package/lib/adaptors/McpAdaptor.js.map +1 -1
  6. package/lib/adaptors/WebSocketAdaptor.js +124 -32
  7. package/lib/adaptors/WebSocketAdaptor.js.map +1 -1
  8. package/lib/adaptors/internal/RoutePathMatcher.d.ts +1 -0
  9. package/lib/adaptors/internal/RoutePathMatcher.js +88 -0
  10. package/lib/adaptors/internal/RoutePathMatcher.js.map +1 -0
  11. package/lib/adaptors/internal/external_context.d.ts +1 -0
  12. package/lib/adaptors/internal/external_context.js +43 -0
  13. package/lib/adaptors/internal/external_context.js.map +1 -0
  14. package/lib/decorators/EncryptedBody.js +2 -2
  15. package/lib/decorators/EncryptedBody.js.map +1 -1
  16. package/lib/decorators/EncryptedController.js +1 -1
  17. package/lib/decorators/EncryptedController.js.map +1 -1
  18. package/lib/decorators/EncryptedModule.d.ts +7 -3
  19. package/lib/decorators/EncryptedModule.js +69 -15
  20. package/lib/decorators/EncryptedModule.js.map +1 -1
  21. package/lib/decorators/EncryptedRoute.js +7 -2
  22. package/lib/decorators/EncryptedRoute.js.map +1 -1
  23. package/lib/decorators/TypedBody.d.ts +1 -1
  24. package/lib/decorators/TypedBody.js +1 -1
  25. package/lib/decorators/TypedFormData.d.ts +22 -8
  26. package/lib/decorators/TypedFormData.js +116 -31
  27. package/lib/decorators/TypedFormData.js.map +1 -1
  28. package/lib/decorators/TypedParam.d.ts +3 -3
  29. package/lib/decorators/TypedParam.js +3 -3
  30. package/lib/decorators/TypedQuery.d.ts +1 -1
  31. package/lib/decorators/TypedQuery.js +9 -4
  32. package/lib/decorators/TypedQuery.js.map +1 -1
  33. package/lib/decorators/internal/EncryptedConstant.js +13 -2
  34. package/lib/decorators/internal/EncryptedConstant.js.map +1 -1
  35. package/lib/decorators/internal/get_encryption_password.d.ts +1 -0
  36. package/lib/decorators/internal/get_encryption_password.js +14 -0
  37. package/lib/decorators/internal/get_encryption_password.js.map +1 -0
  38. package/lib/decorators/internal/get_path_and_querify.js +21 -3
  39. package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
  40. package/lib/decorators/internal/get_text_body.js +9 -3
  41. package/lib/decorators/internal/get_text_body.js.map +1 -1
  42. package/lib/decorators/internal/group_entries.d.ts +1 -0
  43. package/lib/decorators/internal/group_entries.js +19 -0
  44. package/lib/decorators/internal/group_entries.js.map +1 -0
  45. package/lib/decorators/internal/validate_request_form_data.js +3 -1
  46. package/lib/decorators/internal/validate_request_form_data.js.map +1 -1
  47. package/lib/decorators/internal/validate_request_headers.js +2 -1
  48. package/lib/decorators/internal/validate_request_headers.js.map +1 -1
  49. package/lib/decorators/internal/validate_request_query.js +3 -1
  50. package/lib/decorators/internal/validate_request_query.js.map +1 -1
  51. package/lib/options/IResponseBodyQuerifier.d.ts +5 -1
  52. package/lib/utils/ExceptionManager.d.ts +3 -4
  53. package/lib/utils/ExceptionManager.js +10 -6
  54. package/lib/utils/ExceptionManager.js.map +1 -1
  55. package/lib/utils/SourceFinder.js +26 -3
  56. package/lib/utils/SourceFinder.js.map +1 -1
  57. package/lib/utils/VersioningStrategy.d.ts +9 -1
  58. package/lib/utils/VersioningStrategy.js +18 -6
  59. package/lib/utils/VersioningStrategy.js.map +1 -1
  60. package/native/go.mod +1 -1
  61. package/native/go.sum +2 -2
  62. package/native/transform/ast.go +4 -2
  63. package/native/transform/core_querify.go +26 -6
  64. package/native/transform/core_transform.go +76 -1
  65. package/native/transform/core_websocket.go +94 -13
  66. package/native/transform/node_transform.go +6 -0
  67. package/native/transform/transform.go +8 -18
  68. package/native/transform/typia_fast.go +6 -0
  69. package/native/transform.cjs +49 -0
  70. package/package.json +14 -17
  71. package/src/adaptors/McpAdaptor.ts +150 -28
  72. package/src/adaptors/WebSocketAdaptor.ts +136 -38
  73. package/src/adaptors/internal/RoutePathMatcher.ts +91 -0
  74. package/src/adaptors/internal/external_context.ts +50 -0
  75. package/src/decorators/EncryptedBody.ts +2 -2
  76. package/src/decorators/EncryptedController.ts +6 -2
  77. package/src/decorators/EncryptedModule.ts +71 -15
  78. package/src/decorators/EncryptedRoute.ts +7 -5
  79. package/src/decorators/TypedBody.ts +1 -1
  80. package/src/decorators/TypedFormData.ts +148 -44
  81. package/src/decorators/TypedParam.ts +3 -3
  82. package/src/decorators/TypedQuery.ts +19 -7
  83. package/src/decorators/internal/EncryptedConstant.ts +14 -1
  84. package/src/decorators/internal/get_encryption_password.ts +19 -0
  85. package/src/decorators/internal/get_path_and_querify.ts +29 -2
  86. package/src/decorators/internal/get_text_body.ts +8 -4
  87. package/src/decorators/internal/group_entries.ts +17 -0
  88. package/src/decorators/internal/validate_request_form_data.ts +3 -1
  89. package/src/decorators/internal/validate_request_headers.ts +2 -2
  90. package/src/decorators/internal/validate_request_query.ts +3 -2
  91. package/src/options/IResponseBodyQuerifier.ts +6 -1
  92. package/src/utils/ExceptionManager.ts +10 -6
  93. package/src/utils/SourceFinder.ts +24 -3
  94. package/src/utils/VersioningStrategy.ts +21 -7
  95. package/lib/transform.d.ts +0 -10
  96. package/lib/transform.js +0 -25
  97. package/lib/transform.js.map +0 -1
  98. package/src/transform.ts +0 -26
@@ -11,18 +11,17 @@ import { Creator } from "../typings/Creator";
11
11
  * {@link EncryptedRoute} instead of the basic router decorator functions like
12
12
  * {@link nest.Get} or {@link nest.Post} and the API function throws a custom
13
13
  * error whose class has been {@link ExceptionManager.insert inserted} in this
14
- * `EntityManager`, the error would be automatically converted to the regular
14
+ * `ExceptionManager`, the error would be automatically converted to the regular
15
15
  * {@link nest.HttpException} instance by the {@link ExceptionManager.Closure}
16
16
  * function.
17
17
  *
18
18
  * Therefore, with this `ExceptionManager` and {@link TypedRoute} or
19
19
  * {@link EncryptedRoute}, you can manage your custom error classes much
20
- * systemtically. You can avoid 500 internal server error or hard coding
20
+ * systematically. You can avoid 500 internal server error or hard coding
21
21
  * implementation about the custom error classes.
22
22
  *
23
- * Below error classes are defaultly configured in this `ExceptionManager`
23
+ * Below error class is configured in this `ExceptionManager` by default.
24
24
  *
25
- * - `typia.TypeGuardError`
26
25
  * - `@nestia/fetcher.HttpError`
27
26
  *
28
27
  * @author Jeongho Nam - https://github.com/samchon
@@ -14,18 +14,17 @@ const common_1 = require("@nestjs/common");
14
14
  * {@link EncryptedRoute} instead of the basic router decorator functions like
15
15
  * {@link nest.Get} or {@link nest.Post} and the API function throws a custom
16
16
  * error whose class has been {@link ExceptionManager.insert inserted} in this
17
- * `EntityManager`, the error would be automatically converted to the regular
17
+ * `ExceptionManager`, the error would be automatically converted to the regular
18
18
  * {@link nest.HttpException} instance by the {@link ExceptionManager.Closure}
19
19
  * function.
20
20
  *
21
21
  * Therefore, with this `ExceptionManager` and {@link TypedRoute} or
22
22
  * {@link EncryptedRoute}, you can manage your custom error classes much
23
- * systemtically. You can avoid 500 internal server error or hard coding
23
+ * systematically. You can avoid 500 internal server error or hard coding
24
24
  * implementation about the custom error classes.
25
25
  *
26
- * Below error classes are defaultly configured in this `ExceptionManager`
26
+ * Below error class is configured in this `ExceptionManager` by default.
27
27
  *
28
- * - `typia.TypeGuardError`
29
28
  * - `@nestia/fetcher.HttpError`
30
29
  *
31
30
  * @author Jeongho Nam - https://github.com/samchon
@@ -45,8 +44,13 @@ var ExceptionManager;
45
44
  const index = ExceptionManager.tuples.findIndex((tuple) => tuple[0] === creator);
46
45
  if (index !== -1)
47
46
  ExceptionManager.tuples.splice(index, 1);
48
- ExceptionManager.tuples.push([creator, closure]);
49
- ExceptionManager.tuples.sort(([x], [y]) => (x.prototype instanceof y ? -1 : 1));
47
+ // an error converts by the first class it is an instance of, so a class
48
+ // must precede every superclass of it: insert before the first one
49
+ const ancestor = ExceptionManager.tuples.findIndex(([registered]) => creator.prototype instanceof registered);
50
+ if (ancestor === -1)
51
+ ExceptionManager.tuples.push([creator, closure]);
52
+ else
53
+ ExceptionManager.tuples.splice(ancestor, 0, [creator, closure]);
50
54
  }
51
55
  ExceptionManager.insert = insert;
52
56
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ExceptionManager.js","sourceRoot":"","sources":["../../src/utils/ExceptionManager.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAC5C,2CAA+C;AAI/C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,IAAiB,gBAAgB,CAsEhC;AAtED,WAAiB,gBAAgB;IAC/B;;;;;;;;OAQG;IACH,SAAgB,MAAM,CACpB,OAAmB,EACnB,OAAmB;QAEnB,MAAM,KAAK,GAAW,uBAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,uBAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAE1C,uBAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAChC,uBAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IATe,iBAAA,MAAM,SASrB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,KAAK,CAAkB,OAAmB;QACxD,MAAM,KAAK,GAAW,uBAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAE/B,uBAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IANe,iBAAA,KAAK,QAMpB,CAAA;IAED,SAAgB,EAAE,CAAC,OAA4B;QAC7C,0BAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAFe,iBAAA,EAAE,KAEjB,CAAA;IAED,SAAgB,GAAG,CAAC,OAA4B;QAC9C,0BAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAFe,iBAAA,GAAG,MAElB,CAAA;IAwBD,gBAAgB;IACH,uBAAM,GAAwC,EAAE,CAAC;IAE9D,gBAAgB;IACH,0BAAS,GAA6B,IAAI,GAAG,EAAE,CAAC;AAC/D,CAAC,EAtEgB,gBAAgB,aAAhB,gBAAgB,GAAhB,gBAAgB,QAsEhC;AAED,gBAAgB,CAAC,MAAM,CACrB,mBAAS,EACT,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,sBAAa,CACf;IACE,IAAI,EAAE,KAAK,CAAC,IAAI;IAChB,OAAO,EAAE,KAAK,CAAC,OAAO;CACvB,EACD,KAAK,CAAC,MAAM,CACb,CACJ,CAAC"}
1
+ {"version":3,"file":"ExceptionManager.js","sourceRoot":"","sources":["../../src/utils/ExceptionManager.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAC5C,2CAA+C;AAI/C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,IAAiB,gBAAgB,CA2EhC;AA3ED,WAAiB,gBAAgB;IAC/B;;;;;;;;OAQG;IACH,SAAgB,MAAM,CACpB,OAAmB,EACnB,OAAmB;QAEnB,MAAM,KAAK,GAAW,uBAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,uBAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAE1C,wEAAwE;QACxE,mEAAmE;QACnE,MAAM,QAAQ,GAAW,uBAAM,CAAC,SAAS,CACvC,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,YAAY,UAAU,CAC1D,CAAC;QACF,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,uBAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;;YAChD,uBAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,CAAC;IAde,iBAAA,MAAM,SAcrB,CAAA;IAED;;;;;OAKG;IACH,SAAgB,KAAK,CAAkB,OAAmB;QACxD,MAAM,KAAK,GAAW,uBAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QACxE,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAE/B,uBAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IANe,iBAAA,KAAK,QAMpB,CAAA;IAED,SAAgB,EAAE,CAAC,OAA4B;QAC7C,0BAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAFe,iBAAA,EAAE,KAEjB,CAAA;IAED,SAAgB,GAAG,CAAC,OAA4B;QAC9C,0BAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAFe,iBAAA,GAAG,MAElB,CAAA;IAwBD,gBAAgB;IACH,uBAAM,GAAwC,EAAE,CAAC;IAE9D,gBAAgB;IACH,0BAAS,GAA6B,IAAI,GAAG,EAAE,CAAC;AAC/D,CAAC,EA3EgB,gBAAgB,aAAhB,gBAAgB,GAAhB,gBAAgB,QA2EhC;AAED,gBAAgB,CAAC,MAAM,CACrB,mBAAS,EACT,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,sBAAa,CACf;IACE,IAAI,EAAE,KAAK,CAAC,IAAI;IAChB,OAAO,EAAE,KAAK,CAAC,OAAO;CACvB,EACD,KAAK,CAAC,MAAM,CACb,CACJ,CAAC"}
@@ -28,7 +28,7 @@ var SourceFinder;
28
28
  });
29
29
  const emplace = (filter) => (input) => (closure) => __awaiter(this, void 0, void 0, function* () {
30
30
  for (const pattern of input) {
31
- for (const file of yield _Glob(path_1.default.resolve(pattern))) {
31
+ for (const file of yield _Glob(pattern)) {
32
32
  const stats = yield fs_1.default.promises.stat(file);
33
33
  if (stats.isDirectory() === true)
34
34
  yield iterate(filter)(closure)(file);
@@ -48,9 +48,32 @@ var SourceFinder;
48
48
  closure(next);
49
49
  }
50
50
  });
51
+ /**
52
+ * Files and directories a path or glob pattern names.
53
+ *
54
+ * An existing path is taken literally, whatever characters it holds, as a
55
+ * directory such as `app [v2]` would otherwise read as a character class. For
56
+ * a pattern, the longest existing ancestor is the literal base and only the
57
+ * rest is globbed, with `/` separators, since glob reads a Windows backslash
58
+ * as an escape.
59
+ */
51
60
  const _Glob = (pattern) => __awaiter(this, void 0, void 0, function* () {
52
- const matches = yield (0, glob_1.glob)(pattern);
53
- return matches.map((str) => path_1.default.resolve(str));
61
+ const absolute = path_1.default.resolve(pattern);
62
+ if (fs_1.default.existsSync(absolute))
63
+ return [absolute];
64
+ let base = absolute;
65
+ while (fs_1.default.existsSync(base) === false) {
66
+ const parent = path_1.default.dirname(base);
67
+ if (parent === base)
68
+ return [];
69
+ base = parent;
70
+ }
71
+ const rest = path_1.default
72
+ .relative(base, absolute)
73
+ .split(path_1.default.sep)
74
+ .join("/");
75
+ const matches = yield (0, glob_1.glob)(rest, { cwd: base });
76
+ return matches.map((str) => path_1.default.resolve(base, str));
54
77
  });
55
78
  })(SourceFinder || (exports.SourceFinder = SourceFinder = {}));
56
79
  //# sourceMappingURL=SourceFinder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SourceFinder.js","sourceRoot":"","sources":["../../src/utils/SourceFinder.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,4CAAoB;AACpB,+BAA4B;AAC5B,gDAAwB;AAExB,IAAiB,YAAY,CA2C5B;AA3CD,WAAiB,YAAY;IACd,iBAAI,GAAG,CAAO,KAAa,EAAqB,EAAE;;QAC7D,MAAM,IAAI,GAAgB,IAAI,GAAG,EAAE,CAAC;QAEpC,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACnE,IAAI,MAAA,KAAK,CAAC,OAAO,0CAAE,MAAM;YACvB,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAExE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACnB,CAAC,CAAA,CAAC;IAEF,MAAM,OAAO,GACX,CAAC,MAAiC,EAAE,EAAE,CACtC,CAAC,KAAe,EAAE,EAAE,CACpB,CAAO,OAAmC,EAAiB,EAAE;QAC3D,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;YAC5B,KAAK,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;gBACtD,MAAM,KAAK,GAAa,MAAM,YAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrD,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,IAAI;oBAC9B,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;qBAClC,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC,CAAA,CAAC;IAEJ,MAAM,OAAO,GACX,CAAC,MAAqC,EAAE,EAAE,CAC1C,CAAC,OAAmC,EAAE,EAAE,CACxC,CAAO,QAAgB,EAAiB,EAAE;QACxC,MAAM,SAAS,GAAa,MAAM,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAChE,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAW,cAAI,CAAC,OAAO,CAAC,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;YACzD,MAAM,KAAK,GAAa,MAAM,YAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAErD,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,IAAI;gBAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;iBAClE,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CAAA,CAAC;IAEJ,MAAM,KAAK,GAAG,CAAO,OAAe,EAAqB,EAAE;QACzD,MAAM,OAAO,GAAG,MAAM,IAAA,WAAI,EAAC,OAAO,CAAC,CAAC;QACpC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACjD,CAAC,CAAA,CAAC;AACJ,CAAC,EA3CgB,YAAY,aAAZ,YAAY,GAAZ,YAAY,QA2C5B"}
1
+ {"version":3,"file":"SourceFinder.js","sourceRoot":"","sources":["../../src/utils/SourceFinder.ts"],"names":[],"mappings":"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"}
@@ -5,5 +5,13 @@ export declare namespace VersioningStrategy {
5
5
  defaultVersion?: VersionValue;
6
6
  }
7
7
  const cast: (value: VersionValue | undefined) => Array<string | typeof VERSION_NEUTRAL>;
8
- const merge: (config: IConfig | undefined) => (values: Array<string | typeof VERSION_NEUTRAL>) => string[];
8
+ /**
9
+ * Version path segments of a route, resolved as NestJS resolves them: the
10
+ * method's versions, else the controller's, else the default version, and no
11
+ * version at all is the unversioned path (#1735).
12
+ */
13
+ const merge: (config: IConfig | undefined) => (props: {
14
+ controller: Array<string | typeof VERSION_NEUTRAL> | undefined;
15
+ method: Array<string | typeof VERSION_NEUTRAL> | undefined;
16
+ }) => string[];
9
17
  }
@@ -4,14 +4,26 @@ exports.VersioningStrategy = void 0;
4
4
  var VersioningStrategy;
5
5
  (function (VersioningStrategy) {
6
6
  VersioningStrategy.cast = (value) => value === undefined ? [] : Array.isArray(value) ? value : [value];
7
- VersioningStrategy.merge = (config) => (values) => {
7
+ /**
8
+ * Version path segments of a route, resolved as NestJS resolves them: the
9
+ * method's versions, else the controller's, else the default version, and no
10
+ * version at all is the unversioned path (#1735).
11
+ */
12
+ VersioningStrategy.merge = (config) => (props) => {
13
+ var _a, _b;
8
14
  if (config === undefined)
9
15
  return [""];
10
- const set = new Set(values);
11
- const array = set.size === 0 ? VersioningStrategy.cast(config.defaultVersion) : Array.from(set);
12
- return !!(array === null || array === void 0 ? void 0 : array.length)
13
- ? array.map((x) => typeof x === "symbol" ? "" : `${config.prefix}${x}`)
14
- : [];
16
+ const chosen = ((_a = props.method) === null || _a === void 0 ? void 0 : _a.length)
17
+ ? props.method
18
+ : ((_b = props.controller) === null || _b === void 0 ? void 0 : _b.length)
19
+ ? props.controller
20
+ : VersioningStrategy.cast(config.defaultVersion);
21
+ const unique = [
22
+ ...new Set(chosen),
23
+ ];
24
+ return unique.length
25
+ ? unique.map((x) => typeof x === "symbol" ? "" : `${config.prefix}${x}`)
26
+ : [""];
15
27
  };
16
28
  })(VersioningStrategy || (exports.VersioningStrategy = VersioningStrategy = {}));
17
29
  //# sourceMappingURL=VersioningStrategy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VersioningStrategy.js","sourceRoot":"","sources":["../../src/utils/VersioningStrategy.ts"],"names":[],"mappings":";;;AAEA,IAAiB,kBAAkB,CAwBlC;AAxBD,WAAiB,kBAAkB;IAMpB,uBAAI,GAAG,CAClB,KAA+B,EACS,EAAE,CAC1C,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAEvD,wBAAK,GAChB,CAAC,MAA2B,EAAE,EAAE,CAChC,CAAC,MAA8C,EAAY,EAAE;QAC3D,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,GAAG,GAAyC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,KAAK,GACT,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,uBAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,EAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,CAAA;YACpB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACd,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CACpD;YACH,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC;AACN,CAAC,EAxBgB,kBAAkB,aAAlB,kBAAkB,GAAlB,kBAAkB,QAwBlC"}
1
+ {"version":3,"file":"VersioningStrategy.js","sourceRoot":"","sources":["../../src/utils/VersioningStrategy.ts"],"names":[],"mappings":";;;AAEA,IAAiB,kBAAkB,CAsClC;AAtCD,WAAiB,kBAAkB;IAMpB,uBAAI,GAAG,CAClB,KAA+B,EACS,EAAE,CAC1C,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAEpE;;;;OAIG;IACU,wBAAK,GAChB,CAAC,MAA2B,EAAE,EAAE,CAChC,CAAC,KAGA,EAAY,EAAE;;QACb,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,MAAM,GAA2C,CAAA,MAAA,KAAK,CAAC,MAAM,0CAC/D,MAAM;YACR,CAAC,CAAC,KAAK,CAAC,MAAM;YACd,CAAC,CAAC,CAAA,MAAA,KAAK,CAAC,UAAU,0CAAE,MAAM;gBACxB,CAAC,CAAC,KAAK,CAAC,UAAU;gBAClB,CAAC,CAAC,uBAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAClC,MAAM,MAAM,GAA2C;YACrD,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC;SACnB,CAAC;QACF,OAAO,MAAM,CAAC,MAAM;YAClB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACf,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CACpD;YACH,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACX,CAAC,CAAC;AACN,CAAC,EAtCgB,kBAAkB,aAAlB,kBAAkB,GAAlB,kBAAkB,QAsClC"}
package/native/go.mod CHANGED
@@ -10,7 +10,7 @@ require (
10
10
  github.com/microsoft/typescript-go/shim/printer v0.0.0
11
11
  github.com/microsoft/typescript-go/shim/scanner v0.0.0
12
12
  github.com/samchon/ttsc/packages/ttsc v0.0.0
13
- github.com/samchon/typia/packages/typia/native v0.0.0-20260818045905-f692fd63a846
13
+ github.com/samchon/typia/packages/typia/native v0.0.0-20260922081121-78124b0523b4
14
14
  )
15
15
 
16
16
  require (
package/native/go.sum CHANGED
@@ -38,8 +38,8 @@ github.com/samchon/ttsc/packages/ttsc/shim/vfs/cachedvfs v0.0.0-20260820075544-3
38
38
  github.com/samchon/ttsc/packages/ttsc/shim/vfs/cachedvfs v0.0.0-20260820075544-3fe6b732f888/go.mod h1:XS3LhXkn5xadyRe3tW+9+suW/7gh7dPdL43Q+s/lUDo=
39
39
  github.com/samchon/ttsc/packages/ttsc/shim/vfs/osvfs v0.0.0-20260820075544-3fe6b732f888 h1:ihiKD2OhuYc7Dngxw3uFYbVoiA/xuPwwQoUakB59E40=
40
40
  github.com/samchon/ttsc/packages/ttsc/shim/vfs/osvfs v0.0.0-20260820075544-3fe6b732f888/go.mod h1:otX+qw8aZLNCoBmCwMAn53Nw0RQTPzSoId3DxmE67So=
41
- github.com/samchon/typia/packages/typia/native v0.0.0-20260818045905-f692fd63a846 h1:x9xL0zn2AqPf19lTp8dNal+Ia3cIu0uYnyXlY4mo3QI=
42
- github.com/samchon/typia/packages/typia/native v0.0.0-20260818045905-f692fd63a846/go.mod h1:pUTSG5IZxw8Hohle//RsDXnE+8ZhAus7mPDKFqzvZnk=
41
+ github.com/samchon/typia/packages/typia/native v0.0.0-20260922081121-78124b0523b4 h1:ZL20GliY1kZk/PYHwJX+n5cp8ljx8YToGP1wWFtaOYs=
42
+ github.com/samchon/typia/packages/typia/native v0.0.0-20260922081121-78124b0523b4/go.mod h1:pUTSG5IZxw8Hohle//RsDXnE+8ZhAus7mPDKFqzvZnk=
43
43
  github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
44
44
  github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
45
45
  github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
@@ -7,12 +7,14 @@ import (
7
7
  )
8
8
 
9
9
  // NodeName returns the trimmed identifier text of a named AST node
10
- // (method, parameter, ...). Empty when the node has no name.
10
+ // (method, parameter, ...). Empty when the node has no name. A name that is no
11
+ // identifier, a destructured parameter's `{ a }` or a computed method name's
12
+ // `[key]`, reads as its source, since typescript-go's `Text()` panics on it.
11
13
  func NodeName(node *shimast.Node) string {
12
14
  if node == nil || node.Name() == nil {
13
15
  return ""
14
16
  }
15
- return strings.Trim(node.Name().Text(), "\"'")
17
+ return strings.Trim(shimast.NodeText(node.Name()), "\"'")
16
18
  }
17
19
 
18
20
  // NodeText returns the verbatim source slice spanned by a node.
@@ -1,8 +1,6 @@
1
1
  package transform
2
2
 
3
3
  import (
4
- "fmt"
5
-
6
4
  shimast "github.com/microsoft/typescript-go/shim/ast"
7
5
  shimchecker "github.com/microsoft/typescript-go/shim/checker"
8
6
  shimprinter "github.com/microsoft/typescript-go/shim/printer"
@@ -44,7 +42,13 @@ func nestiaCoreHttpQuerifyProgrammer(prog *driver.Program, ec *shimprinter.EmitC
44
42
  Type: typ,
45
43
  })
46
44
  if result.Success == false {
47
- panic(fmt.Errorf("failed to analyze query-string metadata: %d error(s)", len(result.Errors)))
45
+ panic(nativecontext.TransformerError_from(struct {
46
+ Code string
47
+ Errors []nativecontext.TransformerError_MetadataFactory_IError
48
+ }{
49
+ Code: "nestia.core.TypedQueryRoute",
50
+ Errors: nestiaCoreMetadataErrors(result.Errors),
51
+ }))
48
52
  }
49
53
  statements := []*shimast.Node{
50
54
  nativefactories.StatementFactory.Constant(nativefactories.StatementFactory_ConstantProps{
@@ -149,12 +153,28 @@ func nestiaCoreHttpValidateQuerifyProgrammer(prog *driver.Program, importer *nat
149
153
  Name: "query",
150
154
  Value: nestiaCoreHttpQuerifyProgrammer(prog, ec, typ),
151
155
  }),
156
+ // the object is validated, then querified: validating the
157
+ // URLSearchParams against the object type found every property absent
152
158
  nativefactories.StatementFactory.Constant(nativefactories.StatementFactory_ConstantProps{
153
- Name: "output",
154
- Value: nestiaCoreCall("query", nestiaCoreFactory.NewIdentifier("input")),
159
+ Name: "result",
160
+ Value: nestiaCoreCall("validate", nestiaCoreFactory.NewIdentifier("input")),
155
161
  }),
156
162
  nestiaCoreFactory.NewReturnStatement(nestiaCoreFactory.NewAsExpression(
157
- nestiaCoreCall("validate", nestiaCoreFactory.NewIdentifier("output")),
163
+ nestiaCoreFactory.NewConditionalExpression(
164
+ nestiaCoreFactory.NewPropertyAccessExpression(
165
+ nestiaCoreFactory.NewIdentifier("result"),
166
+ nil,
167
+ nestiaCoreFactory.NewIdentifier("success"),
168
+ shimast.NodeFlagsNone,
169
+ ),
170
+ nil,
171
+ nestiaCoreFactory.NewObjectLiteralExpression(nestiaCoreFactory.NewNodeList([]*shimast.Node{
172
+ nestiaCoreProperty("success", nestiaCoreFactory.NewKeywordExpression(shimast.KindTrueKeyword), ec),
173
+ nestiaCoreProperty("data", nestiaCoreCall("query", nestiaCoreFactory.NewIdentifier("input")), ec),
174
+ }), false),
175
+ nil,
176
+ nestiaCoreFactory.NewIdentifier("result"),
177
+ ),
158
178
  nativefactories.TypeFactory.Keyword("any"),
159
179
  )),
160
180
  })
@@ -94,6 +94,60 @@ type nestiaCoreFileContext struct {
94
94
  coreImports map[string]string
95
95
  }
96
96
 
97
+ // The values the validate and stringify options accept.
98
+ var (
99
+ nestiaCoreValidateModes = []string{
100
+ "assert", "is", "validate", "equals",
101
+ "assertEquals", "validateEquals",
102
+ "assertClone", "validateClone",
103
+ "assertPrune", "validatePrune",
104
+ }
105
+ nestiaCoreStringifyModes = []string{"stringify", "assert", "is", "validate", "validate.log"}
106
+ )
107
+
108
+ // nestiaCoreOptionErrors reports each validate or stringify option value that
109
+ // is no mode: a generator would otherwise take its default branch, and a typo
110
+ // such as "assertEqual" silently weakens validation.
111
+ func nestiaCoreOptionErrors(plan plugin.Plan) []string {
112
+ errors := []string{}
113
+ check := func(name string, value any, modes []string, nullable bool) {
114
+ if value == nil && nullable {
115
+ return
116
+ }
117
+ if text, ok := value.(string); ok {
118
+ for _, mode := range modes {
119
+ if mode == text {
120
+ return
121
+ }
122
+ }
123
+ }
124
+ accepted := "\"" + strings.Join(modes, "\", \"") + "\""
125
+ if nullable {
126
+ accepted += ", or null"
127
+ }
128
+ errors = append(errors, fmt.Sprintf("invalid %q option %s: it must be one of %s.", name, nestiaCoreOptionText(value), accepted))
129
+ }
130
+ for _, entry := range plan.Entries {
131
+ if entry.Name != "@nestia/core" && !strings.Contains(entry.Transform, "@nestia/core") {
132
+ continue
133
+ }
134
+ if value, ok := entry.Config["validate"]; ok {
135
+ check("validate", value, nestiaCoreValidateModes, false)
136
+ }
137
+ if value, ok := entry.Config["stringify"]; ok {
138
+ check("stringify", value, nestiaCoreStringifyModes, true)
139
+ }
140
+ }
141
+ return errors
142
+ }
143
+
144
+ func nestiaCoreOptionText(value any) string {
145
+ if text, ok := value.(string); ok {
146
+ return fmt.Sprintf("%q", text)
147
+ }
148
+ return fmt.Sprintf("%v", value)
149
+ }
150
+
97
151
  func readNestiaCoreOptions(plan plugin.Plan) nestiaCoreOptions {
98
152
  options := nestiaCoreOptions{}
99
153
  for _, entry := range plan.Entries {
@@ -174,6 +228,19 @@ func nestiaCoreDecoratorCall(prog *driver.Program, decorator *shimast.Node) (*sh
174
228
  return call, canonical, true
175
229
  }
176
230
 
231
+ // NestiaCoreCanonicalDecoratorSegments names a decorator call's callee by the
232
+ // @nestia/core export its import binds, so `import { TypedException as TE }`
233
+ // reads `TE<T>()` as `TypedException`. It returns nil for a decorator that is
234
+ // no call.
235
+ func NestiaCoreCanonicalDecoratorSegments(decorator *shimast.Node) []string {
236
+ _, segments, ok := nestiaCoreRawDecoratorCall(decorator)
237
+ if !ok {
238
+ return nil
239
+ }
240
+ context := newNestiaCoreFileContext(shimast.GetSourceFileOfNode(decorator))
241
+ return nestiaCoreCanonicalSegments(context, segments)
242
+ }
243
+
177
244
  func newNestiaCoreFileContext(file *shimast.SourceFile) nestiaCoreFileContext {
178
245
  context := nestiaCoreFileContext{
179
246
  file: file,
@@ -538,7 +605,13 @@ func nestiaCoreFormDataFiles(prog *driver.Program, typ *shimchecker.Type) []nest
538
605
  Type: typ,
539
606
  })
540
607
  if result.Success == false {
541
- panic(fmt.Errorf("failed to analyze form-data metadata: %d error(s)", len(result.Errors)))
608
+ panic(nativecontext.TransformerError_from(struct {
609
+ Code string
610
+ Errors []nativecontext.TransformerError_MetadataFactory_IError
611
+ }{
612
+ Code: "nestia.core.TypedFormDataBody",
613
+ Errors: nestiaCoreMetadataErrors(result.Errors),
614
+ }))
542
615
  }
543
616
  files := []nestiaCoreFormDataFile{}
544
617
  if result.Data == nil || len(result.Data.Objects) == 0 || result.Data.Objects[0] == nil || result.Data.Objects[0].Type == nil {
@@ -678,6 +751,8 @@ func nestiaCoreGenerateTypedQueryRoute(prog *driver.Program, importer *nativecon
678
751
  return nestiaCoreValidatorObject("type", "validate", nestiaCoreHttpValidateQuerifyProgrammer(prog, importer, ec, modulo, typ), ec)
679
752
  case "stringify":
680
753
  return nestiaCoreValidatorObject("type", "stringify", nestiaCoreHttpQuerifyProgrammer(prog, ec, typ), ec)
754
+ case "validate.log":
755
+ return nestiaCoreValidatorObjectWithKey("type", "validate.log", "validate", nestiaCoreHttpValidateQuerifyProgrammer(prog, importer, ec, modulo, typ), ec)
681
756
  default:
682
757
  return nestiaCoreValidatorObject("type", "assert", nestiaCoreHttpAssertQuerifyProgrammer(prog, importer, ec, modulo, typ), ec)
683
758
  }
@@ -2,9 +2,11 @@ package transform
2
2
 
3
3
  import (
4
4
  "fmt"
5
+ "path/filepath"
5
6
  "strings"
6
7
 
7
8
  shimast "github.com/microsoft/typescript-go/shim/ast"
9
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
8
10
  shimscanner "github.com/microsoft/typescript-go/shim/scanner"
9
11
  "github.com/samchon/ttsc/packages/ttsc/driver"
10
12
  )
@@ -42,14 +44,14 @@ func validateNestiaCoreWebSocketRoute(
42
44
  switch category {
43
45
  case "Acceptor":
44
46
  accepted = true
45
- if strings.HasPrefix(nestiaCoreWebSocketParameterTypeName(param), "WebSocketAcceptor") == false {
47
+ if _, target := NestiaCoreWebSocketTypeReference(prog, nestiaCoreWebSocketParameterTypeNode(param)); target != "WebSocketAcceptor" {
46
48
  diagnostics = append(diagnostics, nestiaCoreWebSocketDiagnostic(context.file, param, "WebSocketRoute", fmt.Sprintf(
47
49
  "parameter %q must have WebSocketAcceptor<Header, Provider, Listener> type.",
48
50
  name,
49
51
  )))
50
52
  }
51
53
  case "Driver":
52
- if strings.HasPrefix(nestiaCoreWebSocketParameterTypeName(param), "Driver") == false {
54
+ if _, target := NestiaCoreWebSocketTypeReference(prog, nestiaCoreWebSocketParameterTypeNode(param)); target != "Driver" {
53
55
  diagnostics = append(diagnostics, nestiaCoreWebSocketDiagnostic(context.file, param, "WebSocketRoute", fmt.Sprintf(
54
56
  "parameter %q must have Driver<Listener> type.",
55
57
  name,
@@ -66,6 +68,12 @@ func validateNestiaCoreWebSocketRoute(
66
68
  return diagnostics
67
69
  }
68
70
 
71
+ // NestiaCoreWebSocketParameterCategory names the WebSocketRoute parameter
72
+ // decorator on a parameter, such as "Acceptor" or "Driver", or "" for none.
73
+ func NestiaCoreWebSocketParameterCategory(prog *driver.Program, param *shimast.Node) string {
74
+ return nestiaCoreWebSocketParameterCategory(prog, param)
75
+ }
76
+
69
77
  func nestiaCoreWebSocketParameterCategory(prog *driver.Program, param *shimast.Node) string {
70
78
  if param == nil || len(param.Decorators()) != 1 {
71
79
  return ""
@@ -78,19 +86,90 @@ func nestiaCoreWebSocketParameterCategory(prog *driver.Program, param *shimast.N
78
86
  return segments[len(segments)-1]
79
87
  }
80
88
 
81
- func nestiaCoreWebSocketParameterTypeName(param *shimast.Node) string {
82
- if param == nil || param.AsParameterDeclaration() == nil || param.AsParameterDeclaration().Type == nil {
83
- return ""
89
+ func nestiaCoreWebSocketParameterTypeNode(param *shimast.Node) *shimast.Node {
90
+ if param == nil || param.AsParameterDeclaration() == nil {
91
+ return nil
92
+ }
93
+ return param.AsParameterDeclaration().Type
94
+ }
95
+
96
+ // NestiaCoreWebSocketTypeReference follows a parameter's type annotation
97
+ // through renamed imports, import types, and type aliases to the tgrid type
98
+ // reference it spells, such as `WebSocketAcceptor<Header, Provider, Listener>`
99
+ // or `Driver<Listener>`, so the transform and the SDK accept every spelling of
100
+ // the same type and still reject another type of the same name. It returns the
101
+ // type references it passed, each a type reference or an import type such as
102
+ // `import("tgrid").Driver<Listener>`, from the annotation to the tgrid
103
+ // reference, each after the first written in the type alias the one before it
104
+ // names, and the name tgrid declares the type by; or nil and "" when the
105
+ // annotation leads to no tgrid type.
106
+ func NestiaCoreWebSocketTypeReference(prog *driver.Program, node *shimast.Node) ([]*shimast.Node, string) {
107
+ chain := []*shimast.Node{}
108
+ for depth := 0; node != nil && depth < 32; depth++ {
109
+ if node.Kind == shimast.KindParenthesizedType {
110
+ node = node.AsParenthesizedTypeNode().Type
111
+ continue
112
+ }
113
+ name := nestiaCoreTypeReferenceName(node)
114
+ if name == nil || prog == nil || prog.Checker == nil {
115
+ return nil, ""
116
+ }
117
+ chain = append(chain, node)
118
+ symbol := prog.Checker.GetSymbolAtLocation(name)
119
+ if symbol != nil && symbol.Flags&shimast.SymbolFlagsAlias != 0 {
120
+ if aliased := shimchecker.Checker_getAliasedSymbol(prog.Checker, symbol); aliased != nil {
121
+ symbol = aliased
122
+ }
123
+ }
124
+ if symbol == nil {
125
+ return nil, ""
126
+ }
127
+ if nestiaCoreIsTgridDeclarations(symbol.Declarations) {
128
+ return chain, symbol.Name
129
+ }
130
+ if symbol.Flags&shimast.SymbolFlagsTypeAlias == 0 {
131
+ return nil, ""
132
+ }
133
+ var alias *shimast.Node
134
+ for _, declaration := range symbol.Declarations {
135
+ if declaration != nil && declaration.Kind == shimast.KindTypeAliasDeclaration {
136
+ alias = declaration
137
+ break
138
+ }
139
+ }
140
+ if alias == nil {
141
+ return nil, ""
142
+ }
143
+ node = alias.AsTypeAliasDeclaration().Type
84
144
  }
85
- text := NodeText(param.AsParameterDeclaration().Type)
86
- text = strings.TrimSpace(text)
87
- if index := strings.Index(text, "<"); index >= 0 {
88
- text = text[:index]
145
+ return nil, ""
146
+ }
147
+
148
+ // nestiaCoreTypeReferenceName is the entity a type names: the `A.B` of
149
+ // `A.B<T>`, or the qualifier of an import type such as `import("m").A.B<T>`.
150
+ // It is nil for any other type, including `typeof import("m")`, the type of a
151
+ // module's value.
152
+ func nestiaCoreTypeReferenceName(node *shimast.Node) *shimast.Node {
153
+ switch node.Kind {
154
+ case shimast.KindTypeReference:
155
+ return node.AsTypeReferenceNode().TypeName
156
+ case shimast.KindImportType:
157
+ if node.AsImportTypeNode().IsTypeOf {
158
+ return nil
159
+ }
160
+ return node.AsImportTypeNode().Qualifier
89
161
  }
90
- if index := strings.LastIndex(text, "."); index >= 0 {
91
- text = text[index+1:]
162
+ return nil
163
+ }
164
+
165
+ func nestiaCoreIsTgridDeclarations(declarations []*shimast.Node) bool {
166
+ for _, declaration := range declarations {
167
+ source := shimast.GetSourceFileOfNode(declaration)
168
+ if source != nil && strings.Contains(filepath.ToSlash(source.FileName()), "/tgrid/") {
169
+ return true
170
+ }
92
171
  }
93
- return text
172
+ return false
94
173
  }
95
174
 
96
175
  func nestiaCoreWebSocketDiagnostic(file *shimast.SourceFile, node *shimast.Node, kind string, message string) Diagnostic {
@@ -99,7 +178,9 @@ func nestiaCoreWebSocketDiagnostic(file *shimast.SourceFile, node *shimast.Node,
99
178
  if file != nil {
100
179
  filePath = file.FileName()
101
180
  if node != nil {
102
- if pos := node.Pos(); pos >= 0 {
181
+ // the first token's position: Pos() starts at the leading trivia,
182
+ // the previous line's end and any JSDoc
183
+ if pos := shimscanner.GetTokenPosOfNode(node, file, false); pos >= 0 {
103
184
  l, c := shimscanner.GetECMALineAndByteOffsetOfPosition(file, pos)
104
185
  line, column = l+1, c+1
105
186
  }
@@ -30,6 +30,7 @@ func nestiaCoreNodeTransform(
30
30
  }
31
31
  }
32
32
  options := readNestiaCoreOptions(plan)
33
+ optionErrors := nestiaCoreOptionErrors(plan)
33
34
  strictReported := false
34
35
  return func(ec *shimprinter.EmitContext, sf *shimast.SourceFile) *shimast.SourceFile {
35
36
  if sf == nil || sf.IsDeclarationFile {
@@ -39,6 +40,11 @@ func nestiaCoreNodeTransform(
39
40
  strictReported = true
40
41
  addDiagnostic(nestiaCoreGlobalDiagnostic("@nestia/core", "strict mode is required."))
41
42
  }
43
+ // reported once, with the first file transformed
44
+ for _, message := range optionErrors {
45
+ addDiagnostic(nestiaCoreGlobalDiagnostic("@nestia/core", message))
46
+ }
47
+ optionErrors = nil
42
48
  importer := nativecontext.NewImportProgrammer(nativecontext.ImportProgrammer_IOptions{
43
49
  InternalPrefix: "typia_transform_",
44
50
  Runtime: "typia",
@@ -7,7 +7,6 @@ import (
7
7
  "fmt"
8
8
  "os"
9
9
  "path/filepath"
10
- "regexp"
11
10
  "strings"
12
11
 
13
12
  shimast "github.com/microsoft/typescript-go/shim/ast"
@@ -169,7 +168,14 @@ func runTransformProject(
169
168
  sf := prog.SourceFile(fileName)
170
169
  return sf != nil && prog.TSProgram.IsLibFile(sf)
171
170
  })
172
- schemametadata.MetadataDependency_listen(prog.Checker, collector.Touch)
171
+ // `File` alone is the whole listener this host needs. `Callee` falls back
172
+ // to it, and the two channels differ only in whether a default library
173
+ // withholds a completeness declaration, which this host never makes;
174
+ // `Unbounded` is ignorable for the same reason, since an unreported input
175
+ // is still watched through the reference graph.
176
+ schemametadata.MetadataDependency_listen(prog.Checker, schemametadata.MetadataDependency_IListener{
177
+ File: collector.Touch,
178
+ })
173
179
  defer schemametadata.MetadataDependency_release(prog.Checker)
174
180
  for _, sf := range prog.SourceFiles() {
175
181
  if sf.IsDeclarationFile {
@@ -256,22 +262,6 @@ func SourceFileText(target any) (string, bool) {
256
262
  return file.Text(), true
257
263
  }
258
264
 
259
- // These patterns run once per transformed file in cleanupTypeScriptTransformText
260
- // / normalizeParenthesizedTypeAnnotations. Compiling them at package scope keeps
261
- // the per-file cost to a match instead of a recompile (the SDK `transform` path
262
- // runs this for every emitted source file).
263
- var (
264
- cleanupImportTypeBlockPattern = regexp.MustCompile(`(?m)^import type \{([^{}\n]+)\} from`)
265
- cleanupImportTypeLinePattern = regexp.MustCompile(`^import type \{\s*([^{}\n]+?)\s*\} from`)
266
- cleanupImportBlankLinePattern = regexp.MustCompile(`(?m)(^import [^\n]+;\n)\n+(const |let |var |export )`)
267
- cleanupInputIsParenPattern = regexp.MustCompile(`input is \(([A-Za-z_$][A-Za-z0-9_$.]*)\)`)
268
- cleanupCollapseBlankCallPattern = regexp.MustCompile(`\n\n([A-Za-z_$][A-Za-z0-9_$]*\([^;\n]*\);?)`)
269
- )
270
- var (
271
- normalizeParenArrowTypePattern = regexp.MustCompile(`: \(([A-Za-z_$][A-Za-z0-9_$.]*(<[^()\n;{}]*>)?)\)(\s*=>)`)
272
- normalizeParenNullishPattern = regexp.MustCompile(`\| \((null|undefined)\)`)
273
- )
274
-
275
265
  func transformDiagnosticToCompilerDiagnostic(
276
266
  diag Diagnostic,
277
267
  ) transformCompilerDiagnostic {
@@ -1,6 +1,8 @@
1
1
  package transform
2
2
 
3
3
  import (
4
+ "sync"
5
+
4
6
  shimast "github.com/microsoft/typescript-go/shim/ast"
5
7
  shimprinter "github.com/microsoft/typescript-go/shim/printer"
6
8
  shimscanner "github.com/microsoft/typescript-go/shim/scanner"
@@ -22,6 +24,10 @@ func nestiaTypiaNodeTransform(
22
24
  ) driver.PluginTransform {
23
25
  transformOptions := pluginOptions.TransformOptions()
24
26
  extras := nativecontext.ITypiaContext_Extras{
27
+ // One cache for the whole program, as typia's own hosts share it: left
28
+ // nil, typia makes one per file, and a program-wide analysis such as
29
+ // `llm.evaluation`'s `@probability` scan reruns for every file.
30
+ Shared: &sync.Map{},
25
31
  AddDiagnostic: func(diag *nativecontext.ITypiaDiagnostic) int {
26
32
  addDiagnostic(nestiaTypiaDiagnosticFrom(diag))
27
33
  return 1