@nestia/core 14.0.1 → 14.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/lib/adaptors/McpAdaptor.d.ts +24 -3
  2. package/lib/adaptors/McpAdaptor.js +72 -34
  3. package/lib/adaptors/McpAdaptor.js.map +1 -1
  4. package/lib/adaptors/WebSocketAdaptor.d.ts +37 -0
  5. package/lib/adaptors/WebSocketAdaptor.js +60 -16
  6. package/lib/adaptors/WebSocketAdaptor.js.map +1 -1
  7. package/lib/adaptors/internal/external_context.js +18 -5
  8. package/lib/adaptors/internal/external_context.js.map +1 -1
  9. package/lib/decorators/DynamicModule.d.ts +12 -0
  10. package/lib/decorators/DynamicModule.js +12 -0
  11. package/lib/decorators/DynamicModule.js.map +1 -1
  12. package/lib/decorators/EncryptedBody.d.ts +14 -6
  13. package/lib/decorators/EncryptedBody.js +37 -14
  14. package/lib/decorators/EncryptedBody.js.map +1 -1
  15. package/lib/decorators/EncryptedController.d.ts +6 -1
  16. package/lib/decorators/EncryptedController.js +6 -1
  17. package/lib/decorators/EncryptedController.js.map +1 -1
  18. package/lib/decorators/EncryptedModule.d.ts +18 -3
  19. package/lib/decorators/EncryptedModule.js +18 -3
  20. package/lib/decorators/EncryptedModule.js.map +1 -1
  21. package/lib/decorators/EncryptedRoute.d.ts +20 -11
  22. package/lib/decorators/EncryptedRoute.js +20 -11
  23. package/lib/decorators/EncryptedRoute.js.map +1 -1
  24. package/lib/decorators/HumanRoute.d.ts +5 -0
  25. package/lib/decorators/HumanRoute.js +5 -0
  26. package/lib/decorators/HumanRoute.js.map +1 -1
  27. package/lib/decorators/McpRoute.d.ts +31 -19
  28. package/lib/decorators/McpRoute.js +12 -1
  29. package/lib/decorators/McpRoute.js.map +1 -1
  30. package/lib/decorators/PlainBody.d.ts +7 -1
  31. package/lib/decorators/PlainBody.js +16 -8
  32. package/lib/decorators/PlainBody.js.map +1 -1
  33. package/lib/decorators/SwaggerCustomizer.d.ts +15 -0
  34. package/lib/decorators/SwaggerCustomizer.js +5 -0
  35. package/lib/decorators/SwaggerCustomizer.js.map +1 -1
  36. package/lib/decorators/SwaggerExample.d.ts +51 -22
  37. package/lib/decorators/SwaggerExample.js +35 -22
  38. package/lib/decorators/SwaggerExample.js.map +1 -1
  39. package/lib/decorators/TypedBody.d.ts +9 -2
  40. package/lib/decorators/TypedBody.js +19 -9
  41. package/lib/decorators/TypedBody.js.map +1 -1
  42. package/lib/decorators/TypedException.d.ts +10 -0
  43. package/lib/decorators/TypedFormData.d.ts +59 -1
  44. package/lib/decorators/TypedFormData.js +5 -0
  45. package/lib/decorators/TypedFormData.js.map +1 -1
  46. package/lib/decorators/TypedHeaders.d.ts +5 -0
  47. package/lib/decorators/TypedHeaders.js +5 -0
  48. package/lib/decorators/TypedHeaders.js.map +1 -1
  49. package/lib/decorators/TypedParam.d.ts +9 -0
  50. package/lib/decorators/TypedParam.js +9 -0
  51. package/lib/decorators/TypedParam.js.map +1 -1
  52. package/lib/decorators/TypedQuery.d.ts +16 -0
  53. package/lib/decorators/TypedQuery.js +16 -0
  54. package/lib/decorators/TypedQuery.js.map +1 -1
  55. package/lib/decorators/TypedRoute.d.ts +25 -10
  56. package/lib/decorators/TypedRoute.js +19 -10
  57. package/lib/decorators/TypedRoute.js.map +1 -1
  58. package/lib/decorators/WebSocketRoute.d.ts +18 -1
  59. package/lib/decorators/WebSocketRoute.js +18 -1
  60. package/lib/decorators/WebSocketRoute.js.map +1 -1
  61. package/lib/decorators/doNotThrowTransformError.d.ts +14 -0
  62. package/lib/decorators/doNotThrowTransformError.js +14 -0
  63. package/lib/decorators/doNotThrowTransformError.js.map +1 -1
  64. package/lib/decorators/internal/IRequestBodyValidation.d.ts +66 -0
  65. package/lib/decorators/internal/IRequestBodyValidation.js +3 -0
  66. package/lib/decorators/internal/IRequestBodyValidation.js.map +1 -0
  67. package/lib/decorators/internal/IWebSocketRouteReflect.d.ts +93 -1
  68. package/lib/decorators/internal/get_path_and_querify.js +3 -7
  69. package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
  70. package/lib/decorators/internal/get_path_and_stringify.js +3 -7
  71. package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
  72. package/lib/decorators/internal/load_controller.d.ts +14 -0
  73. package/lib/decorators/internal/load_controller.js +14 -0
  74. package/lib/decorators/internal/load_controller.js.map +1 -1
  75. package/lib/decorators/internal/split_route_arguments.d.ts +1 -0
  76. package/lib/decorators/internal/split_route_arguments.js +22 -0
  77. package/lib/decorators/internal/split_route_arguments.js.map +1 -0
  78. package/lib/decorators/internal/validate_request_body.js +68 -25
  79. package/lib/decorators/internal/validate_request_body.js.map +1 -1
  80. package/lib/options/IRequestBodyValidator.d.ts +71 -0
  81. package/lib/options/IRequestFormDataProps.d.ts +80 -0
  82. package/lib/options/IRequestHeadersValidator.d.ts +67 -0
  83. package/lib/options/IRequestQueryValidator.d.ts +68 -0
  84. package/lib/options/IResponseBodyQuerifier.d.ts +120 -0
  85. package/lib/options/IResponseBodyStringifier.d.ts +107 -0
  86. package/lib/typings/Creator.d.ts +10 -0
  87. package/lib/utils/ArrayUtil.d.ts +21 -0
  88. package/lib/utils/ArrayUtil.js +22 -1
  89. package/lib/utils/ArrayUtil.js.map +1 -1
  90. package/lib/utils/ExceptionManager.d.ts +40 -0
  91. package/lib/utils/ExceptionManager.js +34 -0
  92. package/lib/utils/ExceptionManager.js.map +1 -1
  93. package/lib/utils/SourceFinder.d.ts +22 -0
  94. package/lib/utils/SourceFinder.js +34 -7
  95. package/lib/utils/SourceFinder.js.map +1 -1
  96. package/lib/utils/VersioningStrategy.d.ts +36 -1
  97. package/lib/utils/VersioningStrategy.js +30 -9
  98. package/lib/utils/VersioningStrategy.js.map +1 -1
  99. package/native/go.mod +1 -1
  100. package/native/go.sum +2 -2
  101. package/native/plugin/plan.go +68 -2
  102. package/native/transform/ast.go +19 -1
  103. package/native/transform/build.go +51 -57
  104. package/native/transform/buildoutput/output.go +147 -0
  105. package/native/transform/contributor.go +9 -0
  106. package/native/transform/core_querify.go +37 -3
  107. package/native/transform/core_transform.go +105 -98
  108. package/native/transform/core_websocket.go +21 -5
  109. package/native/transform/node_transform.go +11 -8
  110. package/native/transform/package.go +55 -0
  111. package/native/transform/printer.go +1 -3
  112. package/native/transform/run.go +18 -0
  113. package/native/transform/schemaprojection/project.go +213 -0
  114. package/native/transform/transform.go +21 -0
  115. package/package.json +5 -4
  116. package/src/adaptors/McpAdaptor.ts +86 -26
  117. package/src/adaptors/WebSocketAdaptor.ts +66 -14
  118. package/src/adaptors/internal/external_context.ts +37 -6
  119. package/src/decorators/DynamicModule.ts +12 -0
  120. package/src/decorators/EncryptedBody.ts +37 -13
  121. package/src/decorators/EncryptedController.ts +6 -1
  122. package/src/decorators/EncryptedModule.ts +18 -3
  123. package/src/decorators/EncryptedRoute.ts +20 -11
  124. package/src/decorators/HumanRoute.ts +5 -0
  125. package/src/decorators/McpRoute.ts +31 -19
  126. package/src/decorators/PlainBody.ts +20 -10
  127. package/src/decorators/SwaggerCustomizer.ts +15 -0
  128. package/src/decorators/SwaggerExample.ts +51 -22
  129. package/src/decorators/TypedBody.ts +17 -8
  130. package/src/decorators/TypedException.ts +10 -0
  131. package/src/decorators/TypedFormData.ts +59 -1
  132. package/src/decorators/TypedHeaders.ts +5 -0
  133. package/src/decorators/TypedParam.ts +9 -0
  134. package/src/decorators/TypedQuery.ts +16 -0
  135. package/src/decorators/TypedRoute.ts +25 -10
  136. package/src/decorators/WebSocketRoute.ts +18 -1
  137. package/src/decorators/doNotThrowTransformError.ts +14 -0
  138. package/src/decorators/internal/IMcpRouteReflect.ts +7 -1
  139. package/src/decorators/internal/IRequestBodyValidation.ts +65 -0
  140. package/src/decorators/internal/IWebSocketRouteReflect.ts +95 -1
  141. package/src/decorators/internal/get_path_and_querify.ts +3 -9
  142. package/src/decorators/internal/get_path_and_stringify.ts +3 -9
  143. package/src/decorators/internal/load_controller.ts +14 -0
  144. package/src/decorators/internal/split_route_arguments.ts +20 -0
  145. package/src/decorators/internal/validate_request_body.ts +87 -34
  146. package/src/options/IRequestBodyValidator.ts +71 -0
  147. package/src/options/IRequestFormDataProps.ts +80 -0
  148. package/src/options/IRequestHeadersValidator.ts +67 -0
  149. package/src/options/IRequestQueryValidator.ts +68 -0
  150. package/src/options/IResponseBodyQuerifier.ts +120 -0
  151. package/src/options/IResponseBodyStringifier.ts +107 -0
  152. package/src/typings/Creator.ts +10 -0
  153. package/src/utils/ArrayUtil.ts +22 -3
  154. package/src/utils/ExceptionManager.ts +40 -0
  155. package/src/utils/SourceFinder.ts +38 -7
  156. package/src/utils/VersioningStrategy.ts +43 -13
@@ -1,4 +1,26 @@
1
+ /**
2
+ * Finds source files by path, directory, or glob.
3
+ *
4
+ * @evidence contracts/common.md#principled-implementation The finder resolves each pattern to existing files or directories, walks directories, applies the caller's filter to files only, and subtracts the excluded set, so the result is the included files minus the excluded ones.
5
+ * @evidence contracts/common.md#clear-and-simple-design One public function and private walkers; the caller supplies the filter.
6
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It contains no file names; extensions come from the caller's filter.
7
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
8
+ * @evidence contracts/portability.md#os-neutral-implementation The finder turns each pattern into an absolute native path with `path.resolve` and asks the filesystem itself, through `existsSync`, `stat` and `readdir`, whether a path exists and what it is, so the volume's own case policy and links apply. Only the part of a pattern below its longest existing ancestor is globbed, rewritten from the native separator to `/` because glob reads a Windows backslash as an escape. Remaining assumptions: the case policy of wildcard matching is glob's own platform default and not a probe of the volume, accepted files are keyed by filesystem real path while returned locations retain their discovered spelling, and directory links are followed once per real path in each include or exclude collection, so aliases and cycles do not repeat a traversal.
9
+ */
1
10
  export declare namespace SourceFinder {
11
+ /**
12
+ * Returns the files matched by the include patterns and not by the exclude
13
+ * patterns.
14
+ *
15
+ * A pattern may name a file, a directory that is walked recursively, or a
16
+ * glob. Only files accepted by the filter are returned.
17
+ *
18
+ * @evidence contracts/common.md#principled-implementation A pattern that exists on disk is used as a path; otherwise its longest existing ancestor becomes the base of a glob search, so a pattern with wildcards is matched below the part of the path that exists, and a base that does not exist matches nothing; accepted file identities use filesystem real paths, so includes and exclusions agree across links and case aliases while output retains a discovered native spelling.
19
+ * @evidence contracts/common.md#clear-and-simple-design One function that runs the same collection twice, once adding and once removing.
20
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The result follows the patterns and the filter, with no fixed directory.
21
+ * @evidence contracts/common.md#meaningful-documentation The comment states the pattern forms and the filtering.
22
+ * @evidence contracts/portability.md#os-neutral-implementation An existing path is used literally, so no character glob reads specially is interpreted. Otherwise the nearest existing ancestor, found with `existsSync` and `dirname` until the filesystem root, is the glob's working directory and the matches are resolved against it, so a drive letter or a UNC root never enters the pattern.
23
+ */
2
24
  const find: (props: IProps) => Promise<string[]>;
3
25
  }
4
26
  interface IProps {
@@ -16,34 +16,61 @@ exports.SourceFinder = void 0;
16
16
  const fs_1 = __importDefault(require("fs"));
17
17
  const glob_1 = require("glob");
18
18
  const path_1 = __importDefault(require("path"));
19
+ /**
20
+ * Finds source files by path, directory, or glob.
21
+ *
22
+ * @evidence contracts/common.md#principled-implementation The finder resolves each pattern to existing files or directories, walks directories, applies the caller's filter to files only, and subtracts the excluded set, so the result is the included files minus the excluded ones.
23
+ * @evidence contracts/common.md#clear-and-simple-design One public function and private walkers; the caller supplies the filter.
24
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It contains no file names; extensions come from the caller's filter.
25
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
26
+ * @evidence contracts/portability.md#os-neutral-implementation The finder turns each pattern into an absolute native path with `path.resolve` and asks the filesystem itself, through `existsSync`, `stat` and `readdir`, whether a path exists and what it is, so the volume's own case policy and links apply. Only the part of a pattern below its longest existing ancestor is globbed, rewritten from the native separator to `/` because glob reads a Windows backslash as an escape. Remaining assumptions: the case policy of wildcard matching is glob's own platform default and not a probe of the volume, accepted files are keyed by filesystem real path while returned locations retain their discovered spelling, and directory links are followed once per real path in each include or exclude collection, so aliases and cycles do not repeat a traversal.
27
+ */
19
28
  var SourceFinder;
20
29
  (function (SourceFinder) {
30
+ /**
31
+ * Returns the files matched by the include patterns and not by the exclude
32
+ * patterns.
33
+ *
34
+ * A pattern may name a file, a directory that is walked recursively, or a
35
+ * glob. Only files accepted by the filter are returned.
36
+ *
37
+ * @evidence contracts/common.md#principled-implementation A pattern that exists on disk is used as a path; otherwise its longest existing ancestor becomes the base of a glob search, so a pattern with wildcards is matched below the part of the path that exists, and a base that does not exist matches nothing; accepted file identities use filesystem real paths, so includes and exclusions agree across links and case aliases while output retains a discovered native spelling.
38
+ * @evidence contracts/common.md#clear-and-simple-design One function that runs the same collection twice, once adding and once removing.
39
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The result follows the patterns and the filter, with no fixed directory.
40
+ * @evidence contracts/common.md#meaningful-documentation The comment states the pattern forms and the filtering.
41
+ * @evidence contracts/portability.md#os-neutral-implementation An existing path is used literally, so no character glob reads specially is interpreted. Otherwise the nearest existing ancestor, found with `existsSync` and `dirname` until the filesystem root, is the glob's working directory and the matches are resolved against it, so a drive letter or a UNC root never enters the pattern.
42
+ */
21
43
  SourceFinder.find = (props) => __awaiter(this, void 0, void 0, function* () {
22
44
  var _a;
23
- const dict = new Set();
24
- yield emplace(props.filter)(props.include)((str) => dict.add(str));
45
+ const dict = new Map();
46
+ yield emplace(props.filter)(props.include)((str) => dict.set(fs_1.default.realpathSync.native(str), str));
25
47
  if ((_a = props.exclude) === null || _a === void 0 ? void 0 : _a.length)
26
- yield emplace(props.filter)(props.exclude)((str) => dict.delete(str));
27
- return [...dict];
48
+ yield emplace(props.filter)(props.exclude)((str) => dict.delete(fs_1.default.realpathSync.native(str)));
49
+ return [...dict.values()];
28
50
  });
29
51
  const emplace = (filter) => (input) => (closure) => __awaiter(this, void 0, void 0, function* () {
52
+ const visited = new Set();
30
53
  for (const pattern of input) {
31
54
  for (const file of yield _Glob(pattern)) {
32
55
  const stats = yield fs_1.default.promises.stat(file);
33
56
  if (stats.isDirectory() === true)
34
- yield iterate(filter)(closure)(file);
57
+ yield iterate(filter)(closure)(file, visited);
35
58
  else if (stats.isFile() && filter(file))
36
59
  closure(file);
37
60
  }
38
61
  }
39
62
  });
40
- const iterate = (filter) => (closure) => (location) => __awaiter(this, void 0, void 0, function* () {
63
+ const iterate = (filter) => (closure) => (location, visited) => __awaiter(this, void 0, void 0, function* () {
64
+ const identity = yield fs_1.default.promises.realpath(location);
65
+ if (visited.has(identity))
66
+ return;
67
+ visited.add(identity);
41
68
  const directory = yield fs_1.default.promises.readdir(location);
42
69
  for (const file of directory) {
43
70
  const next = path_1.default.resolve(`${location}/${file}`);
44
71
  const stats = yield fs_1.default.promises.stat(next);
45
72
  if (stats.isDirectory() === true)
46
- yield iterate(filter)(closure)(next);
73
+ yield iterate(filter)(closure)(next, visited);
47
74
  else if (stats.isFile() && filter(next))
48
75
  closure(next);
49
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SourceFinder.js","sourceRoot":"","sources":["../../src/utils/SourceFinder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SourceFinder.js","sourceRoot":"","sources":["../../src/utils/SourceFinder.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,49 @@
1
1
  import { VERSION_NEUTRAL, VersionValue } from "@nestjs/common/interfaces";
2
+ /**
3
+ * Resolves the URI versions of a controller method the way NestJS does.
4
+ *
5
+ * @evidence contracts/common.md#principled-implementation The namespace turns the version metadata of a controller and a method, with the default version of the application, into the version path segments, following NestJS's precedence.
6
+ * @evidence contracts/common.md#clear-and-simple-design Two functions and one configuration type.
7
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The precedence follows NestJS; no version string is special-cased.
8
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
9
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
10
+ */
2
11
  export declare namespace VersioningStrategy {
12
+ /**
13
+ * The URI versioning options the adapter reads: the prefix and the default
14
+ * version.
15
+ *
16
+ * @evidence contracts/common.md#principled-implementation The two fields are what NestJS's URI versioning uses to build a version segment.
17
+ * @evidence contracts/common.md#clear-and-simple-design A two-field record.
18
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It is a type and adds no runtime behavior.
19
+ * @evidence contracts/common.md#meaningful-documentation The comment names the two fields.
20
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
21
+ */
3
22
  interface IConfig {
4
23
  prefix: string;
5
24
  defaultVersion?: VersionValue;
6
25
  }
7
- const cast: (value: VersionValue | undefined) => Array<string | typeof VERSION_NEUTRAL>;
26
+ /**
27
+ * Casts version metadata to a list: a missing value stays absent and a single
28
+ * value is a one-element list.
29
+ *
30
+ * @evidence contracts/common.md#principled-implementation One version becomes a list while absence and an explicit empty list remain distinct, because Nest treats an empty version list as no registered paths rather than inherited versions.
31
+ * @evidence contracts/common.md#clear-and-simple-design One conditional expression.
32
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It adds nothing to the values.
33
+ * @evidence contracts/common.md#meaningful-documentation The comment states the three cases.
34
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
35
+ */
36
+ const cast: (value: VersionValue | undefined) => Array<string | typeof VERSION_NEUTRAL> | undefined;
8
37
  /**
9
38
  * Version path segments of a route, resolved as NestJS resolves them: the
10
39
  * method's versions, else the controller's, else the default version, and no
11
40
  * version at all is the unversioned path (#1735).
41
+ *
42
+ * @evidence contracts/common.md#principled-implementation The first present method, controller or default version list wins, including an empty list that registers no paths. Duplicates are dropped, a neutral version maps to no segment, and absent metadata also maps to no segment; with versioning off the only path has no version.
43
+ * @evidence contracts/common.md#clear-and-simple-design One function returning the segments, curried on the configuration so a caller can compute the segments per method.
44
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The precedence is NestJS's, and no version is special-cased.
45
+ * @evidence contracts/common.md#meaningful-documentation The comment states the precedence and the neutral version rule.
46
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
12
47
  */
13
48
  const merge: (config: IConfig | undefined) => (props: {
14
49
  controller: Array<string | typeof VERSION_NEUTRAL> | undefined;
@@ -1,29 +1,50 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VersioningStrategy = void 0;
4
+ /**
5
+ * Resolves the URI versions of a controller method the way NestJS does.
6
+ *
7
+ * @evidence contracts/common.md#principled-implementation The namespace turns the version metadata of a controller and a method, with the default version of the application, into the version path segments, following NestJS's precedence.
8
+ * @evidence contracts/common.md#clear-and-simple-design Two functions and one configuration type.
9
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The precedence follows NestJS; no version string is special-cased.
10
+ * @evidence contracts/common.md#meaningful-documentation The comment states its purpose.
11
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
12
+ */
4
13
  var VersioningStrategy;
5
14
  (function (VersioningStrategy) {
6
- VersioningStrategy.cast = (value) => value === undefined ? [] : Array.isArray(value) ? value : [value];
15
+ /**
16
+ * Casts version metadata to a list: a missing value stays absent and a single
17
+ * value is a one-element list.
18
+ *
19
+ * @evidence contracts/common.md#principled-implementation One version becomes a list while absence and an explicit empty list remain distinct, because Nest treats an empty version list as no registered paths rather than inherited versions.
20
+ * @evidence contracts/common.md#clear-and-simple-design One conditional expression.
21
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts It adds nothing to the values.
22
+ * @evidence contracts/common.md#meaningful-documentation The comment states the three cases.
23
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
24
+ */
25
+ VersioningStrategy.cast = (value) => value === undefined ? undefined : Array.isArray(value) ? value : [value];
7
26
  /**
8
27
  * Version path segments of a route, resolved as NestJS resolves them: the
9
28
  * method's versions, else the controller's, else the default version, and no
10
29
  * version at all is the unversioned path (#1735).
30
+ *
31
+ * @evidence contracts/common.md#principled-implementation The first present method, controller or default version list wins, including an empty list that registers no paths. Duplicates are dropped, a neutral version maps to no segment, and absent metadata also maps to no segment; with versioning off the only path has no version.
32
+ * @evidence contracts/common.md#clear-and-simple-design One function returning the segments, curried on the configuration so a caller can compute the segments per method.
33
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The precedence is NestJS's, and no version is special-cased.
34
+ * @evidence contracts/common.md#meaningful-documentation The comment states the precedence and the neutral version rule.
35
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation Version precedence and prefix concatenation produce HTTP URI segments and never resolve native filesystem paths.
11
36
  */
12
37
  VersioningStrategy.merge = (config) => (props) => {
13
38
  var _a, _b;
14
39
  if (config === undefined)
15
40
  return [""];
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);
41
+ const chosen = (_b = (_a = props.method) !== null && _a !== void 0 ? _a : props.controller) !== null && _b !== void 0 ? _b : VersioningStrategy.cast(config.defaultVersion);
42
+ if (chosen === undefined)
43
+ return [""];
21
44
  const unique = [
22
45
  ...new Set(chosen),
23
46
  ];
24
- return unique.length
25
- ? unique.map((x) => typeof x === "symbol" ? "" : `${config.prefix}${x}`)
26
- : [""];
47
+ return unique.map((x) => typeof x === "symbol" ? "" : `${config.prefix}${x}`);
27
48
  };
28
49
  })(VersioningStrategy || (exports.VersioningStrategy = VersioningStrategy = {}));
29
50
  //# sourceMappingURL=VersioningStrategy.js.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"VersioningStrategy.js","sourceRoot":"","sources":["../../src/utils/VersioningStrategy.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;GAQG;AACH,IAAiB,kBAAkB,CA2DlC;AA3DD,WAAiB,kBAAkB;IAgBjC;;;;;;;;;OASG;IACU,uBAAI,GAAG,CAClB,KAA+B,EACqB,EAAE,CACtD,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAE3E;;;;;;;;;;OAUG;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,eACV,KAAK,CAAC,MAAM,mCAAI,KAAK,CAAC,UAAU,mCAAI,uBAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAClE,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,MAAM,GAA2C;YACrD,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC;SACnB,CAAC;QACF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACtB,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CACpD,CAAC;IACJ,CAAC,CAAC;AACN,CAAC,EA3DgB,kBAAkB,aAAlB,kBAAkB,GAAlB,kBAAkB,QA2DlC"}
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-20260922081121-78124b0523b4
13
+ github.com/samchon/typia/packages/typia/native v0.0.0-20260926142025-755176823ba3
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-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=
41
+ github.com/samchon/typia/packages/typia/native v0.0.0-20260926142025-755176823ba3 h1:XtRIf6wvDuSHLsphMXiB3lm6p0/2sxHMfc6FMjI5LLA=
42
+ github.com/samchon/typia/packages/typia/native v0.0.0-20260926142025-755176823ba3/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=
@@ -14,6 +14,16 @@ const (
14
14
  TypiaTransform = "typia/lib/transform"
15
15
  )
16
16
 
17
+ // Entry is one plugin of the ordered list that ttsc hands to the host: its name, stage, the `transform` specifier of its configuration, and the whole configuration.
18
+ //
19
+ // @evidence contracts/common.md#principled-implementation The fields are the parts of the payload that classification and option reading need, with the transform specifier lifted out of the configuration map once so every later comparison reads a string.
20
+ // @evidence contracts/common.md#clear-and-simple-design A plain record with no behavior; the two methods answer questions about it.
21
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It carries the payload as given, and no plugin name or option is special-cased here.
22
+ // @evidence contracts/common.md#meaningful-documentation The comment names the fields and where the value comes from.
23
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation Plugin specifiers are module identifiers and configuration is decoded data, not native file identity.
24
+ // @evidenceExclude contracts/performance.md#efficient-algorithms This record defines data rather than choosing a processing algorithm.
25
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This record does not coordinate computations across consumers.
26
+ // @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The parsed entry stores configuration but does not own its consumers lifetimes.
17
27
  type Entry struct {
18
28
  Name string
19
29
  Stage string
@@ -21,6 +31,16 @@ type Entry struct {
21
31
  Config map[string]any
22
32
  }
23
33
 
34
+ // Plan is the parsed plugin list: the entries in order and one flag for each plugin family present.
35
+ //
36
+ // @evidence contracts/common.md#principled-implementation The three flags are computed once by `ParsePlan` from the classification of every entry, so the callers ask a boolean instead of rescanning the list.
37
+ // @evidence contracts/common.md#clear-and-simple-design A record of three flags and the ordered entries, with one derived accessor.
38
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It holds parsed data only, and the flags follow from the entries.
39
+ // @evidence contracts/common.md#meaningful-documentation The comment states what each part of the plan means.
40
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation The ordered plugin list and family flags contain no native paths or process handles.
41
+ // @evidenceExclude contracts/performance.md#efficient-algorithms This record defines data rather than choosing a processing algorithm.
42
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This record does not coordinate computations across consumers.
43
+ // @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The plan stores parsed entries; the command owns their lifetime.
24
44
  type Plan struct {
25
45
  Core bool
26
46
  SDK bool
@@ -28,12 +48,31 @@ type Plan struct {
28
48
  Entries []Entry
29
49
  }
30
50
 
51
+ // UsesNestia reports whether the plan contains a `@nestia/core` or a `@nestia/sdk` entry, that is, whether any nestia rewrite is wanted.
52
+ //
53
+ // @evidence contracts/common.md#principled-implementation The result is the disjunction of the two family flags, which is exactly the condition under which the nestia passes run.
54
+ // @evidence contracts/common.md#clear-and-simple-design A one-line accessor over two fields, so the condition has one definition.
55
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It reads the flags and nothing else.
56
+ // @evidence contracts/common.md#meaningful-documentation The comment states the condition.
57
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation The family-flag predicate reads only booleans.
58
+ // @evidence contracts/performance.md#efficient-algorithms Reading two family flags takes constant work and allocates no collection.
59
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
60
+ // @evidence contracts/performance.md#bound-retention-and-release-resources No state survives the boolean result.
31
61
  func (p Plan) UsesNestia() bool {
32
62
  return p.Core || p.SDK
33
63
  }
34
64
 
35
65
  // Kind reports which plugin family an entry belongs to: "core", "sdk", "typia",
36
66
  // or "" when it is none of them.
67
+ //
68
+ // @evidence contracts/common.md#principled-implementation The family is decided by the entry name or by the `transform` specifier compared with the known published specifiers, so an entry written under either spelling of the plugin is recognized, and any other entry is not a family member.
69
+ // @evidence contracts/common.md#clear-and-simple-design A one-line method over the private classifier, so one function owns the naming rules.
70
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts The names are the published package specifiers, which are contract constants, and no consumer or path is special-cased.
71
+ // @evidence contracts/common.md#meaningful-documentation The comment lists the four possible results.
72
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation Classification compares published module specifiers, not native paths.
73
+ // @evidence contracts/performance.md#efficient-algorithms Classification trims and compares the name and transform strings, linear in their bytes.
74
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
75
+ // @evidence contracts/performance.md#bound-retention-and-release-resources Only temporary trimmed strings are used; no registry entry is retained.
37
76
  func (e Entry) Kind() string {
38
77
  return classify(e)
39
78
  }
@@ -41,6 +80,15 @@ func (e Entry) Kind() string {
41
80
  // BoolConfig reads a boolean option from an entry's resolved plugin config. The
42
81
  // second result distinguishes an option explicitly set to false from one that is
43
82
  // absent, which the tri-state options depend on.
83
+ //
84
+ // @evidence contracts/common.md#principled-implementation A boolean read from the configuration returns its value and a presence flag, so an option explicitly set to false is distinct from an absent one, which the tri-state options need; a non-boolean value reads as absent.
85
+ // @evidence contracts/common.md#clear-and-simple-design One map lookup and one type assertion.
86
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It reads only the configuration of the entry it is called on.
87
+ // @evidence contracts/common.md#meaningful-documentation The comment states why the second result exists.
88
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation The lookup reads an in-memory JSON option map.
89
+ // @evidence contracts/performance.md#efficient-algorithms One map lookup and type assertion use expected constant work.
90
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
91
+ // @evidence contracts/performance.md#bound-retention-and-release-resources The lookup retains no state or handle.
44
92
  func (e Entry) BoolConfig(key string) (bool, bool) {
45
93
  if e.Config == nil {
46
94
  return false, false
@@ -49,13 +97,25 @@ func (e Entry) BoolConfig(key string) (bool, bool) {
49
97
  return value, ok
50
98
  }
51
99
 
100
+ // ParsePlan parses the ordered plugin payload that ttsc passes as `--plugins-json`.
101
+ //
102
+ // An empty payload is an empty plan. A payload that is not a JSON list of plugin objects is an error naming the flag. JSON null is not an empty list, and a null list entry is not a plugin object. An entry without a stage is a `transform` stage entry.
103
+ //
104
+ // @evidence contracts/common.md#principled-implementation The standard JSON decoder checks the list and object field types. A nil decoded list identifies JSON null rather than an empty array; pointer elements retain null entries for explicit rejection. Each object keeps its order, defaults its stage, supplies its transform string and contributes its classified family flag. A rejected list returns a zero plan even when a prior element was valid.
105
+ // @evidence contracts/common.md#clear-and-simple-design One function that decodes, normalizes, and classifies; the string reading and the classification are private helpers.
106
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts The defaults are the ttsc protocol's, and the function trusts the payload only as far as decoding it.
107
+ // @evidence contracts/common.md#meaningful-documentation The comment states the accepted payloads, the error, and the stage default.
108
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation The command payload is a JSON string; plugin transform specifiers remain module identifiers rather than native paths.
109
+ // @evidence contracts/performance.md#efficient-algorithms Decoding is linear in payload bytes and one classification is performed per entry; the output holds one entry per plugin.
110
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
111
+ // @evidence contracts/performance.md#bound-retention-and-release-resources Decoded maps and the result list belong to the returned plan and become reclaimable with its caller.
52
112
  func ParsePlan(payload string) (Plan, error) {
53
113
  payload = strings.TrimSpace(payload)
54
114
  if payload == "" {
55
115
  return Plan{}, nil
56
116
  }
57
117
 
58
- var raws []struct {
118
+ var raws []*struct {
59
119
  Name string `json:"name"`
60
120
  Stage string `json:"stage"`
61
121
  Config map[string]any `json:"config"`
@@ -63,11 +123,17 @@ func ParsePlan(payload string) (Plan, error) {
63
123
  if err := json.Unmarshal([]byte(payload), &raws); err != nil {
64
124
  return Plan{}, fmt.Errorf("parse plugins-json: %w", err)
65
125
  }
126
+ if raws == nil {
127
+ return Plan{}, fmt.Errorf("parse plugins-json: expected a JSON list of plugin objects")
128
+ }
66
129
 
67
130
  plan := Plan{
68
131
  Entries: make([]Entry, 0, len(raws)),
69
132
  }
70
- for _, raw := range raws {
133
+ for index, raw := range raws {
134
+ if raw == nil {
135
+ return Plan{}, fmt.Errorf("parse plugins-json: entry %d must be a JSON object", index)
136
+ }
71
137
  stage := raw.Stage
72
138
  if stage == "" {
73
139
  stage = "transform"
@@ -10,6 +10,15 @@ import (
10
10
  // (method, parameter, ...). Empty when the node has no name. A name that is no
11
11
  // identifier, a destructured parameter's `{ a }` or a computed method name's
12
12
  // `[key]`, reads as its source, since typescript-go's `Text()` panics on it.
13
+ //
14
+ // @evidence contracts/common.md#principled-implementation The identifier text is read through the shim's `NodeText` so that a destructured parameter or a computed method name, whose `Text()` panics in the compiler port, reads as its source, and the quotes of a string-literal name are trimmed.
15
+ // @evidence contracts/common.md#clear-and-simple-design One function with a nil check, one call, and one trim.
16
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It handles the node kinds the compiler API defines, with no fixture names.
17
+ // @evidence contracts/common.md#meaningful-documentation The comment states the empty result, the source fallback for non-identifiers, and the reason.
18
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation The compiler node name is source text, not a filesystem path.
19
+ // @evidence contracts/performance.md#efficient-algorithms Reading NodeText and trimming quote characters cost at most the name text length.
20
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
21
+ // @evidence contracts/performance.md#bound-retention-and-release-resources The returned string borrows or contains source text; the helper retains no node globally.
13
22
  func NodeName(node *shimast.Node) string {
14
23
  if node == nil || node.Name() == nil {
15
24
  return ""
@@ -17,7 +26,16 @@ func NodeName(node *shimast.Node) string {
17
26
  return strings.Trim(shimast.NodeText(node.Name()), "\"'")
18
27
  }
19
28
 
20
- // NodeText returns the verbatim source slice spanned by a node.
29
+ // NodeText returns the source slice spanned by a node with surrounding whitespace removed.
30
+ //
31
+ // @evidence contracts/common.md#principled-implementation The node's position range is applied to the source text of its file after a bounds check, and the slice is trimmed, so a synthesized node or a range outside the source returns an empty string instead of panicking.
32
+ // @evidence contracts/common.md#clear-and-simple-design One function over the source text accessor.
33
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It reads the text of the file the node belongs to and adds nothing to it.
34
+ // @evidence contracts/common.md#meaningful-documentation The comment identifies the source range and whitespace trimming.
35
+ // @evidenceExclude contracts/portability.md#os-neutral-implementation Source text and node byte offsets are compiler data rather than native filesystem access.
36
+ // @evidence contracts/performance.md#efficient-algorithms Bounds checks are constant work and TrimSpace scans at most the selected source range.
37
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
38
+ // @evidence contracts/performance.md#bound-retention-and-release-resources The returned source substring can keep its source string alive until the caller releases it; no global state or handle is acquired.
21
39
  func NodeText(node *shimast.Node) string {
22
40
  if node == nil {
23
41
  return ""
@@ -2,17 +2,16 @@ package transform
2
2
 
3
3
  import (
4
4
  "context"
5
- "encoding/json"
6
5
  "flag"
7
6
  "fmt"
8
7
  "io"
9
8
  "os"
10
9
  "path/filepath"
11
- "sync"
12
10
  "time"
13
11
 
14
12
  shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
15
13
  "github.com/samchon/nestia/packages/core/native/plugin"
14
+ "github.com/samchon/nestia/packages/core/native/transform/buildoutput"
16
15
  "github.com/samchon/ttsc/packages/ttsc/driver"
17
16
  typiaadapter "github.com/samchon/typia/packages/typia/native/adapter"
18
17
  )
@@ -117,18 +116,14 @@ func runBuild(args []string) int {
117
116
  defer prog.Close()
118
117
  releaseTypiaRegistries := registerTypiaDefaultLibraryClassifier(prog)
119
118
  defer releaseTypiaRegistries()
120
- if !*quiet {
121
- fmt.Fprintf(
122
- stdout,
123
- "// ttsc-nestia build: tsconfig=%s cwd=%s core=%v sdk=%v typia=%v emit=%v\n",
124
- *tsconfigPath,
125
- cwd,
126
- plan.Core,
127
- plan.SDK,
128
- plan.Typia,
129
- shouldEmit,
130
- )
131
- }
119
+ publication := buildoutput.New(buildoutput.Options{
120
+ TSConfig: *tsconfigPath, CWD: cwd, Manifest: *manifestPath,
121
+ Core: plan.Core, SDK: plan.SDK, Typia: plan.Typia,
122
+ Emit: shouldEmit, Quiet: *quiet,
123
+ }, stdout, driver.DefaultWriteFile)
124
+ // Publication owns all generated bytes until actual diagnostics accept them.
125
+ // Every earlier return terminates this session without committing its buffer.
126
+ defer publication.Finish(false)
132
127
 
133
128
  // AST-integration emit: typia's per-file transformer and @nestia/core's own
134
129
  // per-file transformer both run inside tsgo's emit pipeline (sharing the
@@ -141,7 +136,13 @@ func runBuild(args []string) int {
141
136
  if profile {
142
137
  started = time.Now()
143
138
  }
144
- newPathsRewriter(prog).applyAll(prog.SourceFiles())
139
+ // Path remapping serves published output, not type analysis. The private
140
+ // ForceEmit program used by noEmit has not run semantic diagnostics, so its
141
+ // checker still resolves imports lazily. Changing those imports to output
142
+ // paths would make it look for JavaScript files that do not exist.
143
+ if shouldEmit {
144
+ newPathsRewriter(prog).applyAll(prog.SourceFiles())
145
+ }
145
146
  profileBuildStep(profile, "paths-rewrite", started)
146
147
 
147
148
  typiaTransform := nestiaTypiaNodeTransform(prog, readTypiaPluginOptions(plan), addDiagnostic)
@@ -160,20 +161,9 @@ func runBuild(args []string) int {
160
161
  }
161
162
  transforms := append([]driver.PluginTransform{typiaTransform, coreTransform}, contributorTransforms...)
162
163
 
163
- emitted := []string{}
164
- pending := []buildPendingOutput{}
165
- var writeMu sync.Mutex
166
164
  writeFile := shimcompiler.WriteFile(func(fileName, text string, data *shimcompiler.WriteFileData) error {
167
165
  _ = data
168
- if shouldEmit {
169
- // TypeScript-Go emits declarations in parallel. Serialize the shared
170
- // slices so buffering cannot lose an artifact or race while the
171
- // declaration workers call this callback concurrently.
172
- writeMu.Lock()
173
- defer writeMu.Unlock()
174
- emitted = append(emitted, fileName)
175
- pending = append(pending, buildPendingOutput{FileName: fileName, Text: text})
176
- }
166
+ publication.Write(fileName, text)
177
167
  return nil
178
168
  })
179
169
 
@@ -215,41 +205,15 @@ func runBuild(args []string) int {
215
205
  if emitHasError {
216
206
  return 3
217
207
  }
218
- if shouldEmit {
219
- for _, output := range pending {
220
- if err := driver.DefaultWriteFile(output.FileName, output.Text); err != nil {
221
- fmt.Fprintf(stderr, "ttsc-nestia build: emit write failed: %v\n", err)
222
- return 3
223
- }
224
- }
225
- if *manifestPath != "" {
226
- data, err := json.Marshal(emitted)
227
- if err != nil {
228
- fmt.Fprintf(stderr, "ttsc-nestia build: manifest marshal failed: %v\n", err)
229
- return 3
230
- }
231
- if err := os.MkdirAll(filepath.Dir(*manifestPath), 0o755); err != nil {
232
- fmt.Fprintf(stderr, "ttsc-nestia build: manifest mkdir failed: %v\n", err)
233
- return 3
234
- }
235
- if err := os.WriteFile(*manifestPath, data, 0o644); err != nil {
236
- fmt.Fprintf(stderr, "ttsc-nestia build: manifest write failed: %v\n", err)
237
- return 3
238
- }
239
- }
240
- if !*quiet {
241
- fmt.Fprintf(stdout, "// ttsc-nestia build: emitted=%d files\n", len(emitted))
242
- }
208
+ if err := publication.Finish(true); err != nil {
209
+ fmt.Fprintf(stderr, "ttsc-nestia build: %v\n", err)
210
+ return 3
243
211
  }
212
+
244
213
  profileBuildStep(profile, "total", totalStarted)
245
214
  return 0
246
215
  }
247
216
 
248
- type buildPendingOutput struct {
249
- FileName string
250
- Text string
251
- }
252
-
253
217
  // emitDeclarations runs tsgo's standard declaration emitter for the program.
254
218
  // tsgo's MarkLinkedReferences pass can nil-panic on some cross-module reference
255
219
  // shapes (e.g. a nestia.config.ts that calls NestFactory.create, compiled by the
@@ -275,6 +239,16 @@ func runCheck(args []string) int {
275
239
  return runBuild(append([]string{"--noEmit"}, args...))
276
240
  }
277
241
 
242
+ // Diagnostic is one transform error: its file, line and column when known, its code, and its message.
243
+ //
244
+ // @evidence contracts/common.md#principled-implementation The record carries what the diagnostic line and the compiler envelope need, and a zero line marks a diagnostic without a position.
245
+ // @evidence contracts/common.md#clear-and-simple-design A five-field record with one formatting method.
246
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts The values come from the transforms that report them.
247
+ // @evidence contracts/common.md#meaningful-documentation The comment names the fields and the meaning of an absent position.
248
+ // @evidence contracts/portability.md#os-neutral-implementation File holds the compiler supplied native source path; formatting delegates native relative-path conversion to filepath.Rel instead of treating it as a URL.
249
+ // @evidenceExclude contracts/performance.md#efficient-algorithms This record defines data rather than choosing a processing algorithm.
250
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This record does not coordinate computations across consumers.
251
+ // @evidenceExclude contracts/performance.md#bound-retention-and-release-resources A diagnostic record stores a path and message; the reporting command owns the collection lifetime.
278
252
  type Diagnostic struct {
279
253
  File string
280
254
  Line int
@@ -283,6 +257,16 @@ type Diagnostic struct {
283
257
  Message string
284
258
  }
285
259
 
260
+ // String formats the diagnostic as `file:line:column - error TS(code): message`, with the file made relative to `cwd` when possible, and without the position when the line is unknown.
261
+ //
262
+ // @evidence contracts/common.md#principled-implementation The path is made relative with `filepath.Rel` and the position part is printed only for a positive line, which is the same shape as every other nestia and typia diagnostic.
263
+ // @evidence contracts/common.md#clear-and-simple-design One function with two format strings.
264
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts The shape is the protocol that ttsc reads from stderr, not a test-specific format.
265
+ // @evidence contracts/common.md#meaningful-documentation The comment states the two formats and the relative path rule.
266
+ // @evidence contracts/portability.md#os-neutral-implementation filepath.Rel represents native path differences, including cross-volume failure which keeps the original path. The position format is diagnostic protocol text.
267
+ // @evidence contracts/performance.md#efficient-algorithms Relative path calculation and formatting are linear in path and message bytes.
268
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
269
+ // @evidence contracts/performance.md#bound-retention-and-release-resources Only the formatted string is returned; no file or writer is opened.
286
270
  func (d Diagnostic) String(cwd string) string {
287
271
  file := d.File
288
272
  if rel, err := filepath.Rel(cwd, file); err == nil {
@@ -294,6 +278,16 @@ func (d Diagnostic) String(cwd string) string {
294
278
  return fmt.Sprintf("%s - error TS(%s): %s", file, d.Code, d.Message)
295
279
  }
296
280
 
281
+ // WriteTypiaTransformDiagnostics writes each diagnostic on its own line to the writer, with files relative to `cwd`.
282
+ //
283
+ // @evidence contracts/common.md#principled-implementation Each diagnostic is written by its own `String`, one per line in the given order, so the output is the concatenation of the formatted diagnostics.
284
+ // @evidence contracts/common.md#clear-and-simple-design One loop over one formatter.
285
+ // @evidence contracts/common.md#prohibited-implementation-shortcuts It writes what it is given, without filtering or reordering.
286
+ // @evidence contracts/common.md#meaningful-documentation The comment states the format and the ordering.
287
+ // @evidence contracts/portability.md#os-neutral-implementation Each diagnostic uses filepath.Rel for native paths and writes through io.Writer; no shell or executable spelling is assembled.
288
+ // @evidence contracts/performance.md#efficient-algorithms Each diagnostic is formatted and written once; work is linear in diagnostic count and total text bytes.
289
+ // @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation does not coordinate equivalent requests; its result is derived from the supplied value or the current command and compiler program.
290
+ // @evidence contracts/performance.md#bound-retention-and-release-resources The writer is caller-owned and remains open; the function retains no diagnostic collection after returning.
297
291
  func WriteTypiaTransformDiagnostics(out io.Writer, diagnostics []Diagnostic, cwd string) {
298
292
  for _, diag := range diagnostics {
299
293
  fmt.Fprintln(out, diag.String(cwd))