@typed/app 1.0.0-beta.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 (116) hide show
  1. package/README.md +166 -0
  2. package/dist/HttpApiVirtualModulePlugin.d.ts +26 -0
  3. package/dist/HttpApiVirtualModulePlugin.d.ts.map +1 -0
  4. package/dist/HttpApiVirtualModulePlugin.js +301 -0
  5. package/dist/RouterVirtualModulePlugin.d.ts +23 -0
  6. package/dist/RouterVirtualModulePlugin.d.ts.map +1 -0
  7. package/dist/RouterVirtualModulePlugin.js +176 -0
  8. package/dist/createTypeInfoApiSessionForApp.d.ts +29 -0
  9. package/dist/createTypeInfoApiSessionForApp.d.ts.map +1 -0
  10. package/dist/createTypeInfoApiSessionForApp.js +46 -0
  11. package/dist/httpapi/defineApiHandler.d.ts +70 -0
  12. package/dist/httpapi/defineApiHandler.d.ts.map +1 -0
  13. package/dist/httpapi/defineApiHandler.js +23 -0
  14. package/dist/index.d.ts +9 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +7 -0
  17. package/dist/internal/appConfigTypes.d.ts +11 -0
  18. package/dist/internal/appConfigTypes.d.ts.map +1 -0
  19. package/dist/internal/appConfigTypes.js +1 -0
  20. package/dist/internal/appLayerTypes.d.ts +24 -0
  21. package/dist/internal/appLayerTypes.d.ts.map +1 -0
  22. package/dist/internal/appLayerTypes.js +28 -0
  23. package/dist/internal/buildRouteDescriptors.d.ts +48 -0
  24. package/dist/internal/buildRouteDescriptors.d.ts.map +1 -0
  25. package/dist/internal/buildRouteDescriptors.js +371 -0
  26. package/dist/internal/emitHttpApiSource.d.ts +18 -0
  27. package/dist/internal/emitHttpApiSource.d.ts.map +1 -0
  28. package/dist/internal/emitHttpApiSource.js +404 -0
  29. package/dist/internal/emitRouterHelpers.d.ts +17 -0
  30. package/dist/internal/emitRouterHelpers.d.ts.map +1 -0
  31. package/dist/internal/emitRouterHelpers.js +74 -0
  32. package/dist/internal/emitRouterSource.d.ts +8 -0
  33. package/dist/internal/emitRouterSource.d.ts.map +1 -0
  34. package/dist/internal/emitRouterSource.js +139 -0
  35. package/dist/internal/extractHttpApiLiterals.d.ts +17 -0
  36. package/dist/internal/extractHttpApiLiterals.d.ts.map +1 -0
  37. package/dist/internal/extractHttpApiLiterals.js +45 -0
  38. package/dist/internal/httpapiDescriptorTree.d.ts +75 -0
  39. package/dist/internal/httpapiDescriptorTree.d.ts.map +1 -0
  40. package/dist/internal/httpapiDescriptorTree.js +182 -0
  41. package/dist/internal/httpapiEndpointContract.d.ts +32 -0
  42. package/dist/internal/httpapiEndpointContract.d.ts.map +1 -0
  43. package/dist/internal/httpapiEndpointContract.js +79 -0
  44. package/dist/internal/httpapiFileRoles.d.ts +67 -0
  45. package/dist/internal/httpapiFileRoles.d.ts.map +1 -0
  46. package/dist/internal/httpapiFileRoles.js +145 -0
  47. package/dist/internal/httpapiId.d.ts +30 -0
  48. package/dist/internal/httpapiId.d.ts.map +1 -0
  49. package/dist/internal/httpapiId.js +57 -0
  50. package/dist/internal/httpapiOpenApiConfig.d.ts +87 -0
  51. package/dist/internal/httpapiOpenApiConfig.d.ts.map +1 -0
  52. package/dist/internal/httpapiOpenApiConfig.js +144 -0
  53. package/dist/internal/httpapiSort.d.ts +16 -0
  54. package/dist/internal/httpapiSort.d.ts.map +1 -0
  55. package/dist/internal/httpapiSort.js +29 -0
  56. package/dist/internal/path.d.ts +16 -0
  57. package/dist/internal/path.d.ts.map +1 -0
  58. package/dist/internal/path.js +38 -0
  59. package/dist/internal/resolveConfig.d.ts +8 -0
  60. package/dist/internal/resolveConfig.d.ts.map +1 -0
  61. package/dist/internal/resolveConfig.js +13 -0
  62. package/dist/internal/routeIdentifiers.d.ts +18 -0
  63. package/dist/internal/routeIdentifiers.d.ts.map +1 -0
  64. package/dist/internal/routeIdentifiers.js +90 -0
  65. package/dist/internal/routeTypeNode.d.ts +45 -0
  66. package/dist/internal/routeTypeNode.d.ts.map +1 -0
  67. package/dist/internal/routeTypeNode.js +93 -0
  68. package/dist/internal/routerDescriptorTree.d.ts +110 -0
  69. package/dist/internal/routerDescriptorTree.d.ts.map +1 -0
  70. package/dist/internal/routerDescriptorTree.js +230 -0
  71. package/dist/internal/typeTargetBootstrap.d.ts +2 -0
  72. package/dist/internal/typeTargetBootstrap.d.ts.map +1 -0
  73. package/dist/internal/typeTargetBootstrap.js +23 -0
  74. package/dist/internal/typeTargetBootstrapHttpApi.d.ts +2 -0
  75. package/dist/internal/typeTargetBootstrapHttpApi.d.ts.map +1 -0
  76. package/dist/internal/typeTargetBootstrapHttpApi.js +21 -0
  77. package/dist/internal/typeTargetSpecs.d.ts +15 -0
  78. package/dist/internal/typeTargetSpecs.d.ts.map +1 -0
  79. package/dist/internal/typeTargetSpecs.js +32 -0
  80. package/dist/internal/validation.d.ts +12 -0
  81. package/dist/internal/validation.d.ts.map +1 -0
  82. package/dist/internal/validation.js +32 -0
  83. package/package.json +45 -0
  84. package/src/HttpApiVirtualModulePlugin.test.ts +1062 -0
  85. package/src/HttpApiVirtualModulePlugin.ts +376 -0
  86. package/src/RouterVirtualModulePlugin.test.ts +1254 -0
  87. package/src/RouterVirtualModulePlugin.ts +242 -0
  88. package/src/createTypeInfoApiSessionForApp.ts +57 -0
  89. package/src/defineApiHandler.test.ts +100 -0
  90. package/src/httpapi/defineApiHandler.ts +141 -0
  91. package/src/httpapiDescriptorTree.test.ts +124 -0
  92. package/src/httpapiEndpointContract.test.ts +160 -0
  93. package/src/httpapiFileRoles.test.ts +105 -0
  94. package/src/index.ts +40 -0
  95. package/src/internal/appConfigTypes.ts +12 -0
  96. package/src/internal/appLayerTypes.ts +79 -0
  97. package/src/internal/buildRouteDescriptors.ts +489 -0
  98. package/src/internal/emitHttpApiSource.ts +563 -0
  99. package/src/internal/emitRouterHelpers.ts +89 -0
  100. package/src/internal/emitRouterSource.ts +191 -0
  101. package/src/internal/extractHttpApiLiterals.ts +67 -0
  102. package/src/internal/httpapiDescriptorTree.ts +283 -0
  103. package/src/internal/httpapiEndpointContract.ts +110 -0
  104. package/src/internal/httpapiFileRoles.ts +204 -0
  105. package/src/internal/httpapiId.ts +78 -0
  106. package/src/internal/httpapiOpenApiConfig.ts +228 -0
  107. package/src/internal/httpapiSort.ts +39 -0
  108. package/src/internal/path.ts +46 -0
  109. package/src/internal/resolveConfig.ts +15 -0
  110. package/src/internal/routeIdentifiers.ts +93 -0
  111. package/src/internal/routeTypeNode.ts +120 -0
  112. package/src/internal/routerDescriptorTree.ts +366 -0
  113. package/src/internal/typeTargetBootstrap.ts +24 -0
  114. package/src/internal/typeTargetBootstrapHttpApi.ts +22 -0
  115. package/src/internal/typeTargetSpecs.ts +35 -0
  116. package/src/internal/validation.ts +46 -0
@@ -0,0 +1,371 @@
1
+ import { basename, dirname, join, relative } from "node:path";
2
+ import { stripScriptExtension, toPosixPath } from "./path.js";
3
+ import { classifyCatchForm, classifyDepsExport, getCallableReturnType, isCallableNode, typeNodeExpectsRefSubjectParam, typeNodeIsEffectOptionReturn, typeNodeIsRouteCompatible, typeNodeToRuntimeKind, } from "./routeTypeNode.js";
4
+ const ENTRYPOINT_EXPORTS = ["handler", "template", "default"];
5
+ const COMPANION_SUFFIXES = [".guard.ts", ".dependencies.ts", ".layout.ts", ".catch.ts"];
6
+ const DIRECTORY_COMPANIONS = new Set(["_guard.ts", "_dependencies.ts", "_layout.ts", "_catch.ts"]);
7
+ const GUARD_EXPORT_NAMES = ["default", "guard"];
8
+ const CATCH_EXPORT_NAMES = ["catch", "catchFn"];
9
+ function isEntryPointExport(name) {
10
+ return ENTRYPOINT_EXPORTS.includes(name);
11
+ }
12
+ function isGuardExportName(name) {
13
+ return GUARD_EXPORT_NAMES.includes(name);
14
+ }
15
+ function isCatchExportName(name) {
16
+ return CATCH_EXPORT_NAMES.includes(name);
17
+ }
18
+ const COMPANION_KIND_TO_SUFFIX = {
19
+ guard: ".guard.ts",
20
+ dependencies: ".dependencies.ts",
21
+ layout: ".layout.ts",
22
+ catch: ".catch.ts",
23
+ };
24
+ const COMPANION_KIND_TO_DIRECTORY_FILE = {
25
+ guard: "_guard.ts",
26
+ dependencies: "_dependencies.ts",
27
+ layout: "_layout.ts",
28
+ catch: "_catch.ts",
29
+ };
30
+ function isCompanionModulePath(absolutePath) {
31
+ const fileName = basename(toPosixPath(absolutePath));
32
+ if (DIRECTORY_COMPANIONS.has(fileName))
33
+ return true;
34
+ return COMPANION_SUFFIXES.some((suffix) => fileName.endsWith(suffix));
35
+ }
36
+ function listEntrypointExports(snapshot) {
37
+ return snapshot.exports.filter((value) => ENTRYPOINT_EXPORTS.some((entrypointName) => entrypointName === value.name));
38
+ }
39
+ function isRouteExportCompatible(routeExport, api) {
40
+ return typeNodeIsRouteCompatible(routeExport.type, api);
41
+ }
42
+ function classifyEntrypointKind(entrypoint, api) {
43
+ const { type } = entrypoint;
44
+ const nodeForKind = isCallableNode(type) ? (getCallableReturnType(type) ?? type) : type;
45
+ return typeNodeToRuntimeKind(nodeForKind, api);
46
+ }
47
+ function getEntryPointName(entrypoint, relPath) {
48
+ if (!isEntryPointExport(entrypoint.name)) {
49
+ return {
50
+ ok: false,
51
+ violation: {
52
+ code: "RVM-ENTRY-003",
53
+ message: `invalid entrypoint export name ${JSON.stringify(entrypoint.name)} in ${relPath}`,
54
+ },
55
+ };
56
+ }
57
+ return { ok: true, value: entrypoint.name };
58
+ }
59
+ function resolveComposedConcernsForLeaf(leafFilePath, existingPaths) {
60
+ const leafDir = dirname(leafFilePath);
61
+ const leafBaseName = basename(stripScriptExtension(leafFilePath));
62
+ const ancestorDirs = [""];
63
+ if (leafDir !== "." && leafDir !== "") {
64
+ const segments = leafDir.split("/").filter(Boolean);
65
+ let acc = "";
66
+ for (const seg of segments) {
67
+ acc = acc ? `${acc}/${seg}` : seg;
68
+ ancestorDirs.push(acc);
69
+ }
70
+ }
71
+ const collectForKind = (kind) => {
72
+ const result = [];
73
+ for (const d of [...ancestorDirs].reverse()) {
74
+ const dirPath = d === "."
75
+ ? COMPANION_KIND_TO_DIRECTORY_FILE[kind]
76
+ : join(d, COMPANION_KIND_TO_DIRECTORY_FILE[kind]);
77
+ const normal = toPosixPath(dirPath);
78
+ if (existingPaths.has(normal))
79
+ result.push(normal);
80
+ }
81
+ const siblingPath = leafDir === "."
82
+ ? `${leafBaseName}${COMPANION_KIND_TO_SUFFIX[kind]}`
83
+ : toPosixPath(join(leafDir, `${leafBaseName}${COMPANION_KIND_TO_SUFFIX[kind]}`));
84
+ if (existingPaths.has(siblingPath))
85
+ result.push(siblingPath);
86
+ return result;
87
+ };
88
+ return {
89
+ guard: collectForKind("guard"),
90
+ dependencies: collectForKind("dependencies"),
91
+ layout: collectForKind("layout"),
92
+ catch: collectForKind("catch"),
93
+ };
94
+ }
95
+ /**
96
+ * Sibling companion path for a leaf file (e.g. "nested/Y.tsx" + "layout" → "nested/Y.layout.ts").
97
+ */
98
+ export function siblingCompanionPath(leafFilePath, kind) {
99
+ const dir = dirname(leafFilePath);
100
+ const base = basename(stripScriptExtension(leafFilePath));
101
+ const file = kind === "dependencies" ? `${base}.dependencies.ts` : `${base}.${kind}.ts`;
102
+ return dir ? toPosixPath(join(dir, file)) : file;
103
+ }
104
+ /**
105
+ * Build route descriptors and validate guards, catches, and dependencies from type info snapshots.
106
+ */
107
+ export function buildRouteDescriptors(snapshots, baseDir, api) {
108
+ const descriptors = [];
109
+ const violations = [];
110
+ const existingPaths = new Set(snapshots.map((s) => toPosixPath(relative(baseDir, s.filePath))));
111
+ for (const snapshot of snapshots) {
112
+ if (isCompanionModulePath(snapshot.filePath))
113
+ continue;
114
+ const entrypoints = listEntrypointExports(snapshot);
115
+ const routeExport = snapshot.exports.find((value) => value.name === "route");
116
+ if (!routeExport) {
117
+ if (entrypoints.length > 0) {
118
+ violations.push({
119
+ code: "RVM-ROUTE-001",
120
+ message: `missing "route" export in ${toPosixPath(relative(baseDir, snapshot.filePath))}`,
121
+ });
122
+ }
123
+ continue;
124
+ }
125
+ if (!isRouteExportCompatible(routeExport, api)) {
126
+ violations.push({
127
+ code: "RVM-ROUTE-002",
128
+ message: `route export is not structurally compatible with Route in ${toPosixPath(relative(baseDir, snapshot.filePath))}`,
129
+ });
130
+ continue;
131
+ }
132
+ if (entrypoints.length === 0) {
133
+ violations.push({
134
+ code: "RVM-ENTRY-001",
135
+ message: `expected one of handler|template|default in ${toPosixPath(relative(baseDir, snapshot.filePath))}`,
136
+ });
137
+ continue;
138
+ }
139
+ if (entrypoints.length > 1) {
140
+ violations.push({
141
+ code: "RVM-ENTRY-002",
142
+ message: `multiple entrypoint exports found in ${toPosixPath(relative(baseDir, snapshot.filePath))}`,
143
+ });
144
+ continue;
145
+ }
146
+ const entrypoint = entrypoints[0];
147
+ const relPath = toPosixPath(relative(baseDir, snapshot.filePath));
148
+ const entrypointNameResult = getEntryPointName(entrypoint, relPath);
149
+ if (!entrypointNameResult.ok) {
150
+ violations.push(entrypointNameResult.violation);
151
+ continue;
152
+ }
153
+ const runtimeKind = classifyEntrypointKind(entrypoint, api);
154
+ if (runtimeKind === "unknown") {
155
+ violations.push({
156
+ code: "RVM-KIND-001",
157
+ message: `handler/template/default runtime kind could not be determined (type targets missing). Ensure route files import from @typed/fx, effect, etc. in ${relPath}`,
158
+ });
159
+ continue;
160
+ }
161
+ const entrypointIsFunction = isCallableNode(entrypoint.type);
162
+ const entrypointExpectsRefSubject = entrypointIsFunction &&
163
+ typeNodeExpectsRefSubjectParam(entrypoint.type, api);
164
+ const composedConcerns = resolveComposedConcernsForLeaf(relPath, existingPaths);
165
+ const inFileConcerns = {};
166
+ for (const name of ["layout", "dependencies", "catch", "guard"]) {
167
+ if (snapshot.exports.some((e) => e.name === name))
168
+ inFileConcerns[name] = true;
169
+ }
170
+ descriptors.push({
171
+ filePath: relPath,
172
+ entrypointExport: entrypointNameResult.value,
173
+ runtimeKind,
174
+ entrypointIsFunction,
175
+ entrypointExpectsRefSubject,
176
+ composedConcerns,
177
+ inFileConcerns,
178
+ routeTypeText: routeExport.type.text,
179
+ });
180
+ }
181
+ const sortedDescriptors = [...descriptors].sort((left, right) => left.filePath.localeCompare(right.filePath));
182
+ const seenRouteIdentity = new Map();
183
+ const ambiguousViolations = [];
184
+ const dedupedDescriptors = [];
185
+ for (const d of sortedDescriptors) {
186
+ const typeKey = d.routeTypeText.replace(/\s+/g, " ").trim();
187
+ const key = `${d.filePath}:${typeKey}`;
188
+ const firstSeen = seenRouteIdentity.get(key);
189
+ if (firstSeen !== undefined) {
190
+ ambiguousViolations.push({
191
+ code: "RVM-AMBIGUOUS-001",
192
+ message: `ambiguous route: same type as ${firstSeen}, also in ${d.filePath}`,
193
+ });
194
+ continue;
195
+ }
196
+ seenRouteIdentity.set(key, d.filePath);
197
+ dedupedDescriptors.push(d);
198
+ }
199
+ const guardViolations = [];
200
+ const guardExportByPath = {};
201
+ const guardPaths = new Set();
202
+ for (const d of dedupedDescriptors) {
203
+ for (const p of d.composedConcerns.guard)
204
+ guardPaths.add(p);
205
+ }
206
+ for (const relPath of guardPaths) {
207
+ const snapshot = snapshots.find((s) => toPosixPath(relative(baseDir, s.filePath)) === relPath);
208
+ if (!snapshot)
209
+ continue;
210
+ const guardExport = snapshot.exports.find((e) => e.name === GUARD_EXPORT_NAMES[0]) ??
211
+ snapshot.exports.find((e) => e.name === GUARD_EXPORT_NAMES[1]);
212
+ if (!guardExport) {
213
+ guardViolations.push({
214
+ code: "RVM-GUARD-001",
215
+ message: `guard file must export "guard" or default: ${relPath}`,
216
+ });
217
+ continue;
218
+ }
219
+ if (!isCallableNode(guardExport.type)) {
220
+ guardViolations.push({
221
+ code: "RVM-GUARD-001",
222
+ message: `guard export must be a function (Effect<Option<*>, *, *>): ${relPath}`,
223
+ });
224
+ continue;
225
+ }
226
+ if (!typeNodeIsEffectOptionReturn(guardExport.type, api)) {
227
+ guardViolations.push({
228
+ code: "RVM-GUARD-001",
229
+ message: `guard return type must be Effect<Option<*>, *, *>: ${relPath}`,
230
+ });
231
+ continue;
232
+ }
233
+ if (!isGuardExportName(guardExport.name)) {
234
+ guardViolations.push({
235
+ code: "RVM-GUARD-001",
236
+ message: `guard export name ${JSON.stringify(guardExport.name)} not in [guard, default]: ${relPath}`,
237
+ });
238
+ continue;
239
+ }
240
+ guardExportByPath[relPath] = guardExport.name;
241
+ }
242
+ const catchExportByPath = {};
243
+ const catchFormByPath = {};
244
+ const depsFormByPath = {};
245
+ const catchPaths = new Set();
246
+ const catchViolations = [];
247
+ for (const d of dedupedDescriptors) {
248
+ for (const p of d.composedConcerns.catch)
249
+ catchPaths.add(p);
250
+ }
251
+ for (const relPath of catchPaths) {
252
+ const snapshot = snapshots.find((s) => toPosixPath(relative(baseDir, s.filePath)) === relPath);
253
+ if (!snapshot)
254
+ continue;
255
+ const catchExport = snapshot.exports.find((e) => e.name === CATCH_EXPORT_NAMES[0]) ??
256
+ snapshot.exports.find((e) => e.name === CATCH_EXPORT_NAMES[1]);
257
+ if (!catchExport) {
258
+ catchViolations.push({
259
+ code: "RVM-CATCH-001",
260
+ message: `catch file must export "catch" or "catchFn": ${relPath}`,
261
+ });
262
+ continue;
263
+ }
264
+ if (!isCatchExportName(catchExport.name)) {
265
+ catchViolations.push({
266
+ code: "RVM-CATCH-001",
267
+ message: `catch export name ${JSON.stringify(catchExport.name)} not in [catch, catchFn]: ${relPath}`,
268
+ });
269
+ continue;
270
+ }
271
+ const catchForm = classifyCatchForm(catchExport.type, api);
272
+ if (catchForm.returnKind === "unknown") {
273
+ catchViolations.push({
274
+ code: "RVM-KIND-001",
275
+ message: `catch return kind could not be determined (type targets missing): ${relPath}`,
276
+ });
277
+ continue;
278
+ }
279
+ catchExportByPath[relPath] = catchExport.name;
280
+ catchFormByPath[relPath] = catchForm;
281
+ }
282
+ for (const d of dedupedDescriptors) {
283
+ if (!d.inFileConcerns.catch)
284
+ continue;
285
+ const snapshot = snapshots.find((s) => toPosixPath(relative(baseDir, s.filePath)) === d.filePath);
286
+ if (!snapshot)
287
+ continue;
288
+ const catchExport = snapshot.exports.find((e) => e.name === CATCH_EXPORT_NAMES[0]) ??
289
+ snapshot.exports.find((e) => e.name === CATCH_EXPORT_NAMES[1]);
290
+ if (catchExport) {
291
+ if (!isCatchExportName(catchExport.name)) {
292
+ catchViolations.push({
293
+ code: "RVM-CATCH-001",
294
+ message: `catch export name ${JSON.stringify(catchExport.name)} not in [catch, catchFn]: ${d.filePath}`,
295
+ });
296
+ continue;
297
+ }
298
+ const catchForm = classifyCatchForm(catchExport.type, api);
299
+ if (catchForm.returnKind === "unknown") {
300
+ catchViolations.push({
301
+ code: "RVM-KIND-001",
302
+ message: `catch return kind could not be determined (type targets missing): ${d.filePath}`,
303
+ });
304
+ }
305
+ else {
306
+ catchExportByPath[d.filePath] = catchExport.name;
307
+ catchFormByPath[d.filePath] = catchForm;
308
+ }
309
+ }
310
+ }
311
+ const depsPaths = new Set();
312
+ for (const d of dedupedDescriptors) {
313
+ for (const p of d.composedConcerns.dependencies) {
314
+ if (basename(p).startsWith("_"))
315
+ depsPaths.add(p);
316
+ }
317
+ }
318
+ const depsViolations = [];
319
+ for (const relPath of depsPaths) {
320
+ const snapshot = snapshots.find((s) => toPosixPath(relative(baseDir, s.filePath)) === relPath);
321
+ if (!snapshot)
322
+ continue;
323
+ const defaultExport = snapshot.exports.find((e) => e.name === "default");
324
+ if (!defaultExport) {
325
+ depsViolations.push({
326
+ code: "RVM-DEPS-001",
327
+ message: `${relPath} is used as directory dependencies but has no default export. Export a default of type Layer, ServiceMap, or Array.`,
328
+ });
329
+ continue;
330
+ }
331
+ const kind = classifyDepsExport(defaultExport.type, api);
332
+ if (kind === "unknown") {
333
+ depsViolations.push({
334
+ code: "RVM-DEPS-001",
335
+ message: `${relPath} default export type could not be determined. Must be Layer, ServiceMap, or Array.`,
336
+ });
337
+ continue;
338
+ }
339
+ depsFormByPath[relPath] = kind;
340
+ }
341
+ const infileCompanionViolations = [];
342
+ for (const d of dedupedDescriptors) {
343
+ for (const kind of ["layout", "dependencies", "catch", "guard"]) {
344
+ if (!d.inFileConcerns[kind])
345
+ continue;
346
+ const siblingPath = siblingCompanionPath(d.filePath, kind);
347
+ if (d.composedConcerns[kind].includes(siblingPath)) {
348
+ infileCompanionViolations.push({
349
+ code: "RVM-INFILE-COMPANION-001",
350
+ message: `${d.filePath} exports "${kind}" in-file and has companion ${siblingPath}; in-file wins but this is ambiguous. Remove one.`,
351
+ });
352
+ }
353
+ }
354
+ }
355
+ const allViolations = [
356
+ ...violations,
357
+ ...ambiguousViolations,
358
+ ...guardViolations,
359
+ ...catchViolations,
360
+ ...depsViolations,
361
+ ...infileCompanionViolations,
362
+ ].sort((left, right) => left.message.localeCompare(right.message));
363
+ return {
364
+ descriptors: dedupedDescriptors,
365
+ violations: allViolations,
366
+ guardExportByPath,
367
+ catchExportByPath,
368
+ catchFormByPath,
369
+ depsFormByPath,
370
+ };
371
+ }
@@ -0,0 +1,18 @@
1
+ import type { HttpApiDescriptorTree } from "./httpapiDescriptorTree.js";
2
+ declare const OPTIONAL_ENDPOINT_EXPORTS: readonly ["headers", "body", "success", "error"];
3
+ type OptionalExport = (typeof OPTIONAL_ENDPOINT_EXPORTS)[number];
4
+ export declare function emitHttpApiSource(input: {
5
+ readonly tree: HttpApiDescriptorTree;
6
+ readonly targetDirectory: string;
7
+ readonly importer: string;
8
+ readonly extractedLiteralsByPath: ReadonlyMap<string, {
9
+ readonly path: string;
10
+ readonly method: string;
11
+ readonly name: string;
12
+ }>;
13
+ readonly optionalExportsByPath: ReadonlyMap<string, ReadonlySet<OptionalExport>>;
14
+ /** When true for an endpoint path, handler returns HttpServerResponse; use handleRaw instead of handle. */
15
+ readonly handlerIsRawByPath?: ReadonlyMap<string, boolean>;
16
+ }): string;
17
+ export {};
18
+ //# sourceMappingURL=emitHttpApiSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitHttpApiSource.d.ts","sourceRoot":"","sources":["../../src/internal/emitHttpApiSource.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,qBAAqB,EAKtB,MAAM,4BAA4B,CAAC;AAgWpC,QAAA,MAAM,yBAAyB,kDAAmD,CAAC;AACnF,KAAK,cAAc,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAUjE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,uBAAuB,EAAE,WAAW,CAC3C,MAAM,EACN;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAC1E,CAAC;IACF,QAAQ,CAAC,qBAAqB,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;IACjF,2GAA2G;IAC3G,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5D,GAAG,MAAM,CA0KT"}