@nestbridge/webpack 2.1.2 → 2.1.4

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.
@@ -1,1463 +1,7 @@
1
- import { dirname, extname, join, posix, relative, resolve, sep } from "node:path";
2
- import { SyntaxKind, isArrayLiteralExpression, isArrayTypeNode, isArrowFunction, isBlock, isCallExpression, isClassDeclaration, isDecorator, isExportDeclaration, isExpressionStatement, isFalseLiteral, isFunctionExpression, isIdentifier, isImportDeclaration, isMethodDeclaration, isNamedExports, isNamedImports, isNewExpression, isNullLiteral, isNumericLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAccessExpression, isPropertyAssignment, isPropertyDeclaration, isReturnStatement, isSpreadElement, isStringLiteral, isStringLiteralLikeNode, isTrueLiteral, isTypeReferenceNode, isUnionTypeNode, isVariableStatement } from "typescript/unstable/ast";
3
- import { API } from "typescript/unstable/sync";
4
- import { existsSync, globSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
5
- import { createUnplugin } from "unplugin";
6
- //#region ../unplugin/build/nestbridge.unplugin.js
7
- var getDecorators = (node) => {
8
- const decorators = node.modifiers?.filter(isDecorator);
9
- return decorators === void 0 || decorators.length === 0 ? void 0 : decorators;
10
- };
11
- var findDecorator = (node, decoratorName) => {
12
- const decorators = getDecorators(node);
13
- if (decorators === void 0) return;
14
- return decorators.find((decorator) => decoratorNameOf(decorator) === decoratorName);
15
- };
16
- var findAnyDecorator = (node, decoratorNames) => {
17
- const decorators = getDecorators(node);
18
- if (decorators === void 0) return;
19
- return decorators.find((decorator) => decoratorNames.includes(decoratorNameOf(decorator) ?? ""));
20
- };
21
- var decoratorNameOf = (decorator) => {
22
- const expression = decorator.expression;
23
- if (isCallExpression(expression) && isIdentifier(expression.expression)) return expression.expression.text;
24
- if (isIdentifier(expression)) return expression.text;
25
- };
26
- var readStaticStringArgument = (decorator) => {
27
- const expression = decorator.expression;
28
- if (!isCallExpression(expression)) return {
29
- ok: true,
30
- value: void 0
31
- };
32
- const [firstArgument] = expression.arguments;
33
- if (firstArgument === void 0) return {
34
- ok: true,
35
- value: void 0
36
- };
37
- if (isStringLiteralLikeNode(firstArgument)) return {
38
- ok: true,
39
- value: firstArgument.text
40
- };
41
- return {
42
- ok: false,
43
- argumentText: firstArgument.getText()
44
- };
45
- };
46
- var HTTP_METHOD_DECORATOR_NAMES = {
47
- Get: "GET",
48
- Post: "POST",
49
- Put: "PUT",
50
- Patch: "PATCH",
51
- Delete: "DELETE"
52
- };
53
- var locationOf = (sourceFile, node) => {
54
- const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
55
- return {
56
- line: line + 1,
57
- column: character + 1
58
- };
59
- };
60
- var SUPPORTED_PARAMETER_DECORATORS = [
61
- "Param",
62
- "Query",
63
- "Body",
64
- "Headers"
65
- ];
66
- var KNOWN_UNSUPPORTED_PARAMETER_DECORATORS = [
67
- "Req",
68
- "Res",
69
- "Request",
70
- "Response"
71
- ];
72
- var extractParameterDefinition = (parameter, index, context) => {
73
- const decorator = findAnyDecorator(parameter, [...SUPPORTED_PARAMETER_DECORATORS, ...KNOWN_UNSUPPORTED_PARAMETER_DECORATORS]);
74
- const location = locationOf(context.sourceFile, parameter);
75
- if (decorator === void 0) {
76
- context.diagnostics.push({
77
- code: "unsupported-parameter",
78
- title: "Unsupported parameter.",
79
- controllerName: context.controllerName,
80
- memberName: context.methodName,
81
- detail: `Parameter "${parameter.name.getText()}" must be decorated with one of @Param, @Query, @Body, or @Headers to be transported through a NestBridge HTTP client.`,
82
- filePath: context.filePath,
83
- line: location.line,
84
- column: location.column
85
- });
86
- return;
87
- }
88
- const decoratorName = decoratorNameOf(decorator);
89
- if (decoratorName !== void 0 && KNOWN_UNSUPPORTED_PARAMETER_DECORATORS.includes(decoratorName)) {
90
- context.diagnostics.push({
91
- code: "unsupported-parameter",
92
- title: "Unsupported parameter.",
93
- controllerName: context.controllerName,
94
- memberName: context.methodName,
95
- detail: `@${decoratorName}() cannot be transported through a NestBridge HTTP client.`,
96
- filePath: context.filePath,
97
- line: location.line,
98
- column: location.column
99
- });
100
- return;
101
- }
102
- if (!isIdentifier(parameter.name)) {
103
- context.diagnostics.push({
104
- code: "unsupported-parameter",
105
- title: "Unsupported parameter.",
106
- controllerName: context.controllerName,
107
- memberName: context.methodName,
108
- detail: "Destructured parameters cannot be transported through a NestBridge HTTP client.",
109
- filePath: context.filePath,
110
- line: location.line,
111
- column: location.column
112
- });
113
- return;
114
- }
115
- const argument = readStaticStringArgument(decorator);
116
- if (!argument.ok) {
117
- context.diagnostics.push({
118
- code: "unsupported-parameter",
119
- title: "Unsupported parameter.",
120
- controllerName: context.controllerName,
121
- memberName: context.methodName,
122
- detail: `@${decoratorName}() arguments must be statically analyzable string literals.`,
123
- found: `@${decoratorName}(${argument.argumentText})`,
124
- filePath: context.filePath,
125
- line: location.line,
126
- column: location.column
127
- });
128
- return;
129
- }
130
- const base = {
131
- index,
132
- parameterName: parameter.name.text
133
- };
134
- if (decoratorName === "Param") {
135
- if (argument.value === void 0) {
136
- context.diagnostics.push({
137
- code: "unsupported-parameter",
138
- title: "Unsupported parameter.",
139
- controllerName: context.controllerName,
140
- memberName: context.methodName,
141
- detail: "A whole @Param() is not supported; provide a route parameter name such as @Param('id').",
142
- filePath: context.filePath,
143
- line: location.line,
144
- column: location.column
145
- });
146
- return;
147
- }
148
- return {
149
- ...base,
150
- kind: "param",
151
- name: argument.value
152
- };
153
- }
154
- if (decoratorName === "Headers") {
155
- if (argument.value === void 0) {
156
- context.diagnostics.push({
157
- code: "unsupported-parameter",
158
- title: "Unsupported parameter.",
159
- controllerName: context.controllerName,
160
- memberName: context.methodName,
161
- detail: "A whole @Headers() is not supported; provide a header name such as @Headers('x-example').",
162
- filePath: context.filePath,
163
- line: location.line,
164
- column: location.column
165
- });
166
- return;
167
- }
168
- return {
169
- ...base,
170
- kind: "header",
171
- name: argument.value
172
- };
173
- }
174
- if (decoratorName === "Query") return {
175
- ...base,
176
- kind: "query",
177
- name: argument.value
178
- };
179
- return {
180
- ...base,
181
- kind: "body",
182
- name: argument.value
183
- };
184
- };
185
- var PRIMITIVE_SCALAR_TYPES = {
186
- string: "String",
187
- number: "Float",
188
- boolean: "Boolean"
189
- };
190
- var unwrapPromise = (typeNode) => {
191
- if (isTypeReferenceNode(typeNode) && isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise" && typeNode.typeArguments?.[0] !== void 0) return unwrapPromise(typeNode.typeArguments[0]);
192
- return typeNode;
193
- };
194
- var unwrapNullable = (typeNode) => {
195
- if (!isUnionTypeNode(typeNode)) return {
196
- inner: typeNode,
197
- isNullable: false
198
- };
199
- const nonNullMembers = typeNode.types.filter((member) => member.kind !== SyntaxKind.NullKeyword && member.kind !== SyntaxKind.UndefinedKeyword);
200
- const [onlyMember] = nonNullMembers;
201
- if (nonNullMembers.length !== 1 || onlyMember === void 0) return {
202
- inner: typeNode,
203
- isNullable: nonNullMembers.length !== typeNode.types.length
204
- };
205
- return {
206
- inner: onlyMember,
207
- isNullable: true
208
- };
209
- };
210
- var unwrapArrayElement = (typeNode) => {
211
- if (isArrayTypeNode(typeNode)) return typeNode.elementType;
212
- if (isTypeReferenceNode(typeNode) && isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Array" && typeNode.typeArguments?.[0] !== void 0) return typeNode.typeArguments[0];
213
- };
214
- var identifierTextOf = (typeNode) => {
215
- if (isTypeReferenceNode(typeNode) && isIdentifier(typeNode.typeName)) return typeNode.typeName.text;
216
- switch (typeNode.kind) {
217
- case SyntaxKind.StringKeyword: return "string";
218
- case SyntaxKind.NumberKeyword: return "number";
219
- case SyntaxKind.BooleanKeyword: return "boolean";
220
- default: return;
221
- }
222
- };
223
- var unwrapTypeNode = (typeNode) => {
224
- const { inner: withoutNullable, isNullable } = unwrapNullable(unwrapPromise(typeNode));
225
- const arrayElement = unwrapArrayElement(withoutNullable);
226
- const identifierText = identifierTextOf(arrayElement === void 0 ? withoutNullable : unwrapNullable(arrayElement).inner);
227
- if (identifierText === void 0) return;
228
- return {
229
- identifierText,
230
- isArray: arrayElement !== void 0,
231
- isNullable
232
- };
233
- };
234
- var graphqlScalarNameFor = (identifierText) => PRIMITIVE_SCALAR_TYPES[identifierText] ?? identifierText;
235
- var graphqlTypeStringFor = (unwrapped, explicitTypeName) => {
236
- const baseName = explicitTypeName ?? graphqlScalarNameFor(unwrapped.identifierText);
237
- const wrapped = unwrapped.isArray ? `[${baseName}!]` : baseName;
238
- return unwrapped.isNullable ? wrapped : `${wrapped}!`;
239
- };
240
- var OBSERVABLE_TYPE_NAME = "Observable";
241
- var STREAMABLE_FILE_TYPE_NAME = "StreamableFile";
242
- var readResponseKind = (returnType) => {
243
- if (returnType === void 0) return "json";
244
- const unwrapped = unwrapPromise(returnType);
245
- if (!isTypeReferenceNode(unwrapped) || !isIdentifier(unwrapped.typeName)) return "json";
246
- if (unwrapped.typeName.text === OBSERVABLE_TYPE_NAME) return "observable";
247
- if (unwrapped.typeName.text === STREAMABLE_FILE_TYPE_NAME) return "stream";
248
- return "json";
249
- };
250
- var trimSlashes = (segment) => segment.replace(/^\/+/, "").replace(/\/+$/, "");
251
- var joinRoutePath = (controllerPath, methodPath) => {
252
- return `/${[trimSlashes(controllerPath), trimSlashes(methodPath ?? "")].filter((segment) => segment.length > 0).join("/")}`;
253
- };
254
- var extractMethodDefinition = (method, context) => {
255
- const decorator = findAnyDecorator(method, Object.keys(HTTP_METHOD_DECORATOR_NAMES));
256
- if (decorator === void 0) return;
257
- const methodName = method.name.getText();
258
- const decoratorName = decoratorNameOf(decorator);
259
- const location = locationOf(context.sourceFile, method);
260
- if (decoratorName === void 0) return;
261
- const httpMethod = HTTP_METHOD_DECORATOR_NAMES[decoratorName];
262
- if (httpMethod === void 0) return;
263
- const routeArgument = readStaticStringArgument(decorator);
264
- if (!routeArgument.ok) {
265
- context.diagnostics.push({
266
- code: "unsupported-route",
267
- title: "Unsupported route.",
268
- controllerName: context.controllerName,
269
- memberName: methodName,
270
- detail: "Route paths must be statically analyzable.",
271
- found: `@${decoratorName}(${routeArgument.argumentText})`,
272
- filePath: context.filePath,
273
- line: location.line,
274
- column: location.column
275
- });
276
- return;
277
- }
278
- const parameters = method.parameters.map((parameter, index) => extractParameterDefinition(parameter, index, {
279
- sourceFile: context.sourceFile,
280
- filePath: context.filePath,
281
- controllerName: context.controllerName,
282
- methodName,
283
- diagnostics: context.diagnostics
284
- }));
285
- if (parameters.some((parameter) => parameter === void 0)) return;
286
- return {
287
- name: methodName,
288
- httpMethod,
289
- path: joinRoutePath(context.controllerPath, routeArgument.value),
290
- parameters: parameters.filter((parameter) => parameter !== void 0),
291
- responseKind: readResponseKind(method.type),
292
- line: location.line,
293
- column: location.column
294
- };
295
- };
296
- var extractControllerDefinition = (classDeclaration, sourceFile, filePath, diagnostics) => {
297
- const controllerName = classDeclaration.name?.text ?? "(anonymous controller)";
298
- const decorator = findDecorator(classDeclaration, "Controller");
299
- if (decorator === void 0) return;
300
- const location = locationOf(sourceFile, classDeclaration);
301
- const argument = readStaticStringArgument(decorator);
302
- if (!argument.ok) {
303
- diagnostics.push({
304
- code: "unsupported-route",
305
- title: "Unsupported route.",
306
- controllerName,
307
- memberName: "",
308
- detail: "Controller paths must be statically analyzable.",
309
- found: `@Controller(${argument.argumentText})`,
310
- filePath,
311
- line: location.line,
312
- column: location.column
313
- });
314
- return;
315
- }
316
- const methods = classDeclaration.members.filter((member) => isMethodDeclaration(member)).map((method) => extractMethodDefinition(method, {
317
- sourceFile,
318
- filePath,
319
- controllerName,
320
- controllerPath: argument.value ?? "",
321
- diagnostics
322
- })).filter((method) => method !== void 0);
323
- return {
324
- name: controllerName,
325
- path: argument.value ?? "",
326
- sourceFile: filePath,
327
- methods
328
- };
329
- };
330
- var findControllerClasses = (sourceFile) => {
331
- return sourceFile.statements.filter((statement) => isClassDeclaration(statement) && findDecorator(statement, "Controller") !== void 0);
332
- };
333
- var sharedApi;
334
- var parseSourceFile = (filePath) => {
335
- sharedApi ??= new API();
336
- sharedApi.updateSnapshot({ closeFiles: [filePath] });
337
- const sourceFile = sharedApi.updateSnapshot({
338
- openFiles: [filePath],
339
- fileChanges: { changed: [filePath] }
340
- }).getDefaultProjectForFile(filePath)?.program.getSourceFile(filePath);
341
- if (sourceFile === void 0) throw new Error(`Unable to parse source file: ${filePath}`);
342
- return sourceFile;
343
- };
344
- var analyzeControllers = (filePaths) => {
345
- const diagnostics = [];
346
- const controllers = [];
347
- for (const filePath of filePaths) {
348
- const sourceFile = parseSourceFile(filePath);
349
- for (const classDeclaration of findControllerClasses(sourceFile)) {
350
- const controller = extractControllerDefinition(classDeclaration, sourceFile, filePath, diagnostics);
351
- if (controller !== void 0) controllers.push(controller);
352
- }
353
- }
354
- return {
355
- controllers,
356
- diagnostics
357
- };
358
- };
359
- var GRAPHQL_OPERATION_DECORATOR_NAMES = {
360
- Query: "query",
361
- Mutation: "mutation"
362
- };
363
- var readTypeThunkExpression = (thunk) => {
364
- if (!isBlock(thunk.body)) return thunk.body;
365
- return thunk.body.statements.find(isReturnStatement)?.expression;
366
- };
367
- var readArgsTypeOption = (decorator) => {
368
- if (!isCallExpression(decorator.expression)) return;
369
- const optionsArgument = decorator.expression.arguments.find(isObjectLiteralExpression);
370
- if (optionsArgument === void 0) return;
371
- const typeProperty = optionsArgument.properties.find((property) => isPropertyAssignment(property) && isIdentifier(property.name) && property.name.text === "type");
372
- if (typeProperty === void 0) return;
373
- const thunk = typeProperty.initializer;
374
- if (!isArrowFunction(thunk) && !isFunctionExpression(thunk)) return;
375
- const returnedExpression = readTypeThunkExpression(thunk);
376
- if (returnedExpression === void 0) return;
377
- if (isArrayLiteralExpression(returnedExpression)) {
378
- const element = returnedExpression.elements[0];
379
- return element !== void 0 && isIdentifier(element) ? {
380
- typeName: element.text,
381
- isArray: true
382
- } : void 0;
383
- }
384
- return isIdentifier(returnedExpression) ? {
385
- typeName: returnedExpression.text,
386
- isArray: false
387
- } : void 0;
388
- };
389
- var extractResolverArgumentDefinition = (parameter, index, context) => {
390
- const decorator = findAnyDecorator(parameter, ["Args"]);
391
- const location = locationOf(context.sourceFile, parameter);
392
- if (decorator === void 0) {
393
- context.diagnostics.push({
394
- code: "unsupported-argument",
395
- title: "Unsupported argument.",
396
- controllerName: context.resolverName,
397
- memberName: context.methodName,
398
- detail: `Parameter "${parameter.name.getText()}" must be decorated with @Args to be transported through a NestBridge GraphQL client.`,
399
- filePath: context.filePath,
400
- line: location.line,
401
- column: location.column
402
- });
403
- return;
404
- }
405
- if (!isIdentifier(parameter.name)) {
406
- context.diagnostics.push({
407
- code: "unsupported-argument",
408
- title: "Unsupported argument.",
409
- controllerName: context.resolverName,
410
- memberName: context.methodName,
411
- detail: "Destructured parameters cannot be transported through a NestBridge GraphQL client.",
412
- filePath: context.filePath,
413
- line: location.line,
414
- column: location.column
415
- });
416
- return;
417
- }
418
- const nameArgument = readStaticStringArgument(decorator);
419
- if (!nameArgument.ok) {
420
- context.diagnostics.push({
421
- code: "unsupported-argument",
422
- title: "Unsupported argument.",
423
- controllerName: context.resolverName,
424
- memberName: context.methodName,
425
- detail: "@Args() name must be a statically analyzable string literal.",
426
- found: `@Args(${nameArgument.argumentText})`,
427
- filePath: context.filePath,
428
- line: location.line,
429
- column: location.column
430
- });
431
- return;
432
- }
433
- if (nameArgument.value === void 0) {
434
- context.diagnostics.push({
435
- code: "unsupported-argument",
436
- title: "Unsupported argument.",
437
- controllerName: context.resolverName,
438
- memberName: context.methodName,
439
- detail: "A whole @Args() is not supported; provide an argument name such as @Args('id').",
440
- filePath: context.filePath,
441
- line: location.line,
442
- column: location.column
443
- });
444
- return;
445
- }
446
- if (parameter.type === void 0) {
447
- context.diagnostics.push({
448
- code: "unsupported-argument",
449
- title: "Unsupported argument.",
450
- controllerName: context.resolverName,
451
- memberName: context.methodName,
452
- detail: `@Args() parameter "${parameter.name.text}" needs an explicit type annotation.`,
453
- filePath: context.filePath,
454
- line: location.line,
455
- column: location.column
456
- });
457
- return;
458
- }
459
- const unwrapped = unwrapTypeNode(parameter.type);
460
- if (unwrapped === void 0) {
461
- context.diagnostics.push({
462
- code: "unsupported-argument",
463
- title: "Unsupported argument.",
464
- controllerName: context.resolverName,
465
- memberName: context.methodName,
466
- detail: `@Args() parameter "${parameter.name.text}" has a type NestBridge cannot statically resolve to a GraphQL type.`,
467
- found: parameter.type.getText(),
468
- filePath: context.filePath,
469
- line: location.line,
470
- column: location.column
471
- });
472
- return;
473
- }
474
- const explicitType = readArgsTypeOption(decorator);
475
- return {
476
- index,
477
- parameterName: parameter.name.text,
478
- name: nameArgument.value,
479
- graphqlType: graphqlTypeStringFor(unwrapped, explicitType?.typeName)
480
- };
481
- };
482
- var parsedFilesByPath = /* @__PURE__ */ new Map();
483
- var parseFile = (filePath) => {
484
- const cached = parsedFilesByPath.get(filePath);
485
- if (cached !== void 0) return cached;
486
- const sourceFile = parseSourceFile(filePath);
487
- parsedFilesByPath.set(filePath, sourceFile);
488
- return sourceFile;
489
- };
490
- var resolveModuleFile = (fromFilePath, moduleSpecifierText) => {
491
- if (!moduleSpecifierText.startsWith(".")) return;
492
- const base = resolve(dirname(fromFilePath), moduleSpecifierText);
493
- return [
494
- `${base}.ts`,
495
- `${base}.tsx`,
496
- resolve(base, "index.ts")
497
- ].find((candidate) => existsSync(candidate));
498
- };
499
- var findExportedDeclaration = (sourceFile, name) => sourceFile.statements.find((statement) => isClassDeclaration(statement) && statement.name?.text === name);
500
- var findImportSource = (sourceFile, localName) => {
501
- for (const statement of sourceFile.statements) {
502
- if (!isImportDeclaration(statement) || !isStringLiteralLikeNode(statement.moduleSpecifier)) continue;
503
- const namedBindings = statement.importClause?.namedBindings;
504
- if (namedBindings === void 0 || !isNamedImports(namedBindings)) continue;
505
- const element = namedBindings.elements.find((candidate) => candidate.name.text === localName);
506
- if (element !== void 0) return {
507
- moduleSpecifierText: statement.moduleSpecifier.text,
508
- importedName: element.propertyName?.text ?? element.name.text
509
- };
510
- }
511
- };
512
- var findReExportSource = (sourceFile, name) => {
513
- for (const statement of sourceFile.statements) {
514
- if (!isExportDeclaration(statement) || statement.moduleSpecifier === void 0 || !isStringLiteralLikeNode(statement.moduleSpecifier)) continue;
515
- if (statement.exportClause === void 0) return statement.moduleSpecifier.text;
516
- if (isNamedExports(statement.exportClause) && statement.exportClause.elements.some((element) => (element.propertyName?.text ?? element.name.text) === name)) return statement.moduleSpecifier.text;
517
- }
518
- };
519
- var resolveClassDeclaration = (name, fromSourceFile, fromFilePath, visited = /* @__PURE__ */ new Set()) => {
520
- if (visited.has(fromFilePath)) return;
521
- visited.add(fromFilePath);
522
- const direct = findExportedDeclaration(fromSourceFile, name);
523
- if (direct !== void 0) return {
524
- classDeclaration: direct,
525
- sourceFile: fromSourceFile,
526
- filePath: fromFilePath
527
- };
528
- const importSource = findImportSource(fromSourceFile, name);
529
- if (importSource !== void 0) {
530
- const resolvedPath = resolveModuleFile(fromFilePath, importSource.moduleSpecifierText);
531
- if (resolvedPath !== void 0) {
532
- const nextSourceFile = parseFile(resolvedPath);
533
- const result = resolveClassDeclaration(importSource.importedName, nextSourceFile, resolvedPath, visited);
534
- if (result !== void 0) return result;
535
- }
536
- }
537
- const reExportModuleSpecifierText = findReExportSource(fromSourceFile, name);
538
- if (reExportModuleSpecifierText !== void 0) {
539
- const resolvedPath = resolveModuleFile(fromFilePath, reExportModuleSpecifierText);
540
- if (resolvedPath !== void 0) return resolveClassDeclaration(name, parseFile(resolvedPath), resolvedPath, visited);
541
- }
542
- };
543
- var PRIMITIVE_SCALAR_NAMES$1 = /* @__PURE__ */ new Set([
544
- "string",
545
- "number",
546
- "boolean"
547
- ]);
548
- var extractSelectionFields = (classDeclaration, sourceFile, filePath, context) => {
549
- const typeName = classDeclaration.name?.text ?? "(anonymous type)";
550
- const location = locationOf(sourceFile, classDeclaration);
551
- if (context.visitedTypeNames.has(typeName)) {
552
- context.diagnostics.push({
553
- code: "circular-type",
554
- title: "Circular type.",
555
- controllerName: context.resolverName,
556
- memberName: context.methodName,
557
- detail: `Type "${typeName}" references itself, directly or indirectly. NestBridge cannot build a finite GraphQL selection set for it.`,
558
- filePath,
559
- line: location.line,
560
- column: location.column
561
- });
562
- return;
563
- }
564
- const nextVisited = new Set(context.visitedTypeNames).add(typeName);
565
- const properties = classDeclaration.members.filter((member) => isPropertyDeclaration(member) && findDecorator(member, "Field") !== void 0);
566
- const fields = [];
567
- for (const property of properties) {
568
- if (!isIdentifier(property.name)) continue;
569
- const fieldName = property.name.text;
570
- const fieldLocation = locationOf(sourceFile, property);
571
- if (property.type === void 0) {
572
- context.diagnostics.push({
573
- code: "unsupported-return-type",
574
- title: "Unsupported field type.",
575
- controllerName: context.resolverName,
576
- memberName: context.methodName,
577
- detail: `Field "${fieldName}" on "${typeName}" needs an explicit type annotation.`,
578
- filePath,
579
- line: fieldLocation.line,
580
- column: fieldLocation.column
581
- });
582
- return;
583
- }
584
- const unwrapped = unwrapTypeNode(property.type);
585
- if (unwrapped === void 0) {
586
- context.diagnostics.push({
587
- code: "unsupported-return-type",
588
- title: "Unsupported field type.",
589
- controllerName: context.resolverName,
590
- memberName: context.methodName,
591
- detail: `Field "${fieldName}" on "${typeName}" has a type NestBridge cannot statically resolve.`,
592
- found: property.type.getText(),
593
- filePath,
594
- line: fieldLocation.line,
595
- column: fieldLocation.column
596
- });
597
- return;
598
- }
599
- if (PRIMITIVE_SCALAR_NAMES$1.has(unwrapped.identifierText)) {
600
- fields.push({ name: fieldName });
601
- continue;
602
- }
603
- const resolved = resolveClassDeclaration(unwrapped.identifierText, sourceFile, filePath);
604
- if (resolved === void 0) {
605
- fields.push({ name: fieldName });
606
- continue;
607
- }
608
- if (findDecorator(resolved.classDeclaration, "ObjectType") === void 0) {
609
- context.diagnostics.push({
610
- code: "unsupported-return-type",
611
- title: "Unsupported field type.",
612
- controllerName: context.resolverName,
613
- memberName: context.methodName,
614
- detail: `Field "${fieldName}" on "${typeName}" resolves to class "${unwrapped.identifierText}", which is not decorated with @ObjectType(). NestBridge cannot build a GraphQL selection set for it.`,
615
- filePath,
616
- line: fieldLocation.line,
617
- column: fieldLocation.column
618
- });
619
- return;
620
- }
621
- const children = extractSelectionFields(resolved.classDeclaration, resolved.sourceFile, resolved.filePath, {
622
- ...context,
623
- visitedTypeNames: nextVisited
624
- });
625
- if (children === void 0) return;
626
- fields.push({
627
- name: fieldName,
628
- children
629
- });
630
- }
631
- return fields;
632
- };
633
- var readNameFromOptions = (optionsArgument) => {
634
- const nameProperty = optionsArgument.properties.find((property) => isPropertyAssignment(property) && isIdentifier(property.name) && property.name.text === "name");
635
- if (nameProperty === void 0 || !isStringLiteralLikeNode(nameProperty.initializer)) return;
636
- return nameProperty.initializer.text;
637
- };
638
- var readGraphqlOperationName = (decorator) => {
639
- const expression = decorator.expression;
640
- if (!isCallExpression(expression)) return {
641
- ok: true,
642
- value: void 0
643
- };
644
- let value;
645
- for (const argument of expression.arguments) {
646
- if (isArrowFunction(argument) || isFunctionExpression(argument)) continue;
647
- if (isStringLiteralLikeNode(argument)) {
648
- value = argument.text;
649
- continue;
650
- }
651
- if (isObjectLiteralExpression(argument)) {
652
- value = readNameFromOptions(argument) ?? value;
653
- continue;
654
- }
655
- return {
656
- ok: false,
657
- argumentText: argument.getText()
658
- };
659
- }
660
- return {
661
- ok: true,
662
- value
663
- };
664
- };
665
- var readGraphqlReturnTypeOption = (decorator) => {
666
- if (!isCallExpression(decorator.expression)) return;
667
- const thunk = decorator.expression.arguments.find((argument) => isArrowFunction(argument) || isFunctionExpression(argument));
668
- if (thunk === void 0) return;
669
- const returnedExpression = readTypeThunkExpression(thunk);
670
- if (returnedExpression === void 0) return;
671
- if (isArrayLiteralExpression(returnedExpression)) {
672
- const element = returnedExpression.elements[0];
673
- return element !== void 0 && isIdentifier(element) ? element.text : void 0;
674
- }
675
- return isIdentifier(returnedExpression) ? returnedExpression.text : void 0;
676
- };
677
- var PRIMITIVE_SCALAR_NAMES = /* @__PURE__ */ new Set([
678
- "string",
679
- "number",
680
- "boolean"
681
- ]);
682
- var extractResolverMethodDefinition = (method, context) => {
683
- const decorator = findAnyDecorator(method, Object.keys(GRAPHQL_OPERATION_DECORATOR_NAMES));
684
- if (decorator === void 0) return;
685
- const methodName = method.name.getText();
686
- const decoratorName = decoratorNameOf(decorator);
687
- const location = locationOf(context.sourceFile, method);
688
- if (decoratorName === void 0) return;
689
- const operationKind = GRAPHQL_OPERATION_DECORATOR_NAMES[decoratorName];
690
- if (operationKind === void 0) return;
691
- const nameArgument = readGraphqlOperationName(decorator);
692
- if (!nameArgument.ok) {
693
- context.diagnostics.push({
694
- code: "unsupported-route",
695
- title: "Unsupported operation name.",
696
- controllerName: context.resolverName,
697
- memberName: methodName,
698
- detail: "GraphQL operation names must be statically analyzable string literals.",
699
- found: `@${decoratorName}(${nameArgument.argumentText})`,
700
- filePath: context.filePath,
701
- line: location.line,
702
- column: location.column
703
- });
704
- return;
705
- }
706
- const decoratorReturnType = readGraphqlReturnTypeOption(decorator);
707
- const identifierText = decoratorReturnType ?? (method.type === void 0 ? void 0 : unwrapTypeNode(method.type)?.identifierText);
708
- if (identifierText === void 0) {
709
- context.diagnostics.push({
710
- code: "unsupported-return-type",
711
- title: "Unsupported return type.",
712
- controllerName: context.resolverName,
713
- memberName: methodName,
714
- detail: "GraphQL resolver methods need a type thunk on @Query()/@Mutation() (e.g. \"() => UserType\") or an explicit return type annotation so NestBridge can build a selection set.",
715
- filePath: context.filePath,
716
- line: location.line,
717
- column: location.column
718
- });
719
- return;
720
- }
721
- let selection = [];
722
- if (!PRIMITIVE_SCALAR_NAMES.has(identifierText.toLowerCase())) {
723
- const resolved = resolveClassDeclaration(identifierText, context.sourceFile, context.filePath);
724
- if (resolved === void 0 && decoratorReturnType === void 0) {
725
- context.diagnostics.push({
726
- code: "unsupported-return-type",
727
- title: "Unsupported return type.",
728
- controllerName: context.resolverName,
729
- memberName: methodName,
730
- detail: `NestBridge could not locate the declaration of type "${identifierText}".`,
731
- filePath: context.filePath,
732
- line: location.line,
733
- column: location.column
734
- });
735
- return;
736
- }
737
- if (resolved !== void 0) {
738
- const fields = extractSelectionFields(resolved.classDeclaration, resolved.sourceFile, resolved.filePath, {
739
- resolverName: context.resolverName,
740
- methodName,
741
- diagnostics: context.diagnostics,
742
- visitedTypeNames: /* @__PURE__ */ new Set()
743
- });
744
- if (fields === void 0) return;
745
- selection = fields;
746
- }
747
- }
748
- const args = method.parameters.map((parameter, index) => extractResolverArgumentDefinition(parameter, index, {
749
- sourceFile: context.sourceFile,
750
- filePath: context.filePath,
751
- resolverName: context.resolverName,
752
- methodName,
753
- diagnostics: context.diagnostics
754
- }));
755
- if (args.some((argument) => argument === void 0)) return;
756
- return {
757
- name: methodName,
758
- operationKind,
759
- operationName: nameArgument.value ?? methodName,
760
- arguments: args.filter((argument) => argument !== void 0),
761
- selection,
762
- line: location.line,
763
- column: location.column
764
- };
765
- };
766
- var extractResolverDefinition = (classDeclaration, sourceFile, filePath, diagnostics) => {
767
- const resolverName = classDeclaration.name?.text ?? "(anonymous resolver)";
768
- return {
769
- name: resolverName,
770
- sourceFile: filePath,
771
- methods: classDeclaration.members.filter((member) => isMethodDeclaration(member)).map((method) => extractResolverMethodDefinition(method, {
772
- sourceFile,
773
- filePath,
774
- resolverName,
775
- diagnostics
776
- })).filter((method) => method !== void 0)
777
- };
778
- };
779
- var findResolverClasses = (sourceFile) => {
780
- return sourceFile.statements.filter((statement) => isClassDeclaration(statement) && findDecorator(statement, "Resolver") !== void 0);
781
- };
782
- var analyzeResolvers = (filePaths) => {
783
- const diagnostics = [];
784
- const resolvers = [];
785
- for (const filePath of filePaths) {
786
- const sourceFile = parseSourceFile(filePath);
787
- for (const classDeclaration of findResolverClasses(sourceFile)) {
788
- const resolver = extractResolverDefinition(classDeclaration, sourceFile, filePath, diagnostics);
789
- if (resolver !== void 0) resolvers.push(resolver);
790
- }
791
- }
792
- return {
793
- resolvers,
794
- diagnostics
795
- };
796
- };
797
- var MODULE_DECORATOR_NAME = "Module";
798
- var PROVIDERS_PROPERTY_NAME = "providers";
799
- var PROVIDE_PROPERTY_NAME = "provide";
800
- var USE_CLASS_PROPERTY_NAME = "useClass";
801
- var APP_FILTER_LOCAL_NAME = "APP_FILTER";
802
- var NEST_CORE_MODULE_SPECIFIER$1 = "@nestjs/core";
803
- var findAppFilterProviderClassName = (moduleClassDeclaration, moduleSourceFile) => {
804
- const moduleDecorator = findDecorator(moduleClassDeclaration, MODULE_DECORATOR_NAME);
805
- if (moduleDecorator === void 0 || !isCallExpression(moduleDecorator.expression)) return;
806
- const [moduleOptions] = moduleDecorator.expression.arguments;
807
- if (moduleOptions === void 0 || !isObjectLiteralExpression(moduleOptions)) return;
808
- const providersProperty = moduleOptions.properties.find((property) => isPropertyAssignment(property) && isIdentifier(property.name) && property.name.text === PROVIDERS_PROPERTY_NAME);
809
- if (providersProperty === void 0 || !isArrayLiteralExpression(providersProperty.initializer)) return;
810
- const appFilterImportSource = findImportSource(moduleSourceFile, APP_FILTER_LOCAL_NAME);
811
- if (appFilterImportSource === void 0 || appFilterImportSource.moduleSpecifierText !== NEST_CORE_MODULE_SPECIFIER$1) return;
812
- const classNames = /* @__PURE__ */ new Set();
813
- for (const element of providersProperty.initializer.elements) {
814
- if (isSpreadElement(element)) return;
815
- if (!isObjectLiteralExpression(element)) continue;
816
- const provideProperty = element.properties.find((property) => isPropertyAssignment(property) && isIdentifier(property.name) && property.name.text === PROVIDE_PROPERTY_NAME);
817
- if (provideProperty === void 0 || !isIdentifier(provideProperty.initializer) || provideProperty.initializer.text !== APP_FILTER_LOCAL_NAME) continue;
818
- const useClassProperty = element.properties.find((property) => isPropertyAssignment(property) && isIdentifier(property.name) && property.name.text === USE_CLASS_PROPERTY_NAME);
819
- if (useClassProperty === void 0 || !isIdentifier(useClassProperty.initializer)) return;
820
- classNames.add(useClassProperty.initializer.text);
821
- }
822
- return classNames.size === 1 ? [...classNames][0] : void 0;
823
- };
824
- var USE_GLOBAL_FILTERS_METHOD_NAME = "useGlobalFilters";
825
- var collectUseGlobalFiltersCalls = (node, calls) => {
826
- if (isCallExpression(node) && isPropertyAccessExpression(node.expression) && node.expression.name.text === USE_GLOBAL_FILTERS_METHOD_NAME) calls.push(node);
827
- node.forEachChild((child) => {
828
- collectUseGlobalFiltersCalls(child, calls);
829
- });
830
- };
831
- var findGlobalFilterClassName = (sourceFile) => {
832
- const calls = [];
833
- collectUseGlobalFiltersCalls(sourceFile, calls);
834
- if (calls.length === 0) return;
835
- const classNames = /* @__PURE__ */ new Set();
836
- for (const call of calls) for (const argument of call.arguments) {
837
- if (!isNewExpression(argument) || !isIdentifier(argument.expression)) return;
838
- classNames.add(argument.expression.text);
839
- }
840
- return classNames.size === 1 ? [...classNames][0] : void 0;
841
- };
842
- var NEST_FACTORY_LOCAL_NAME = "NestFactory";
843
- var NEST_FACTORY_CREATE_METHOD_NAME = "create";
844
- var NEST_CORE_MODULE_SPECIFIER = "@nestjs/core";
845
- var collectNestFactoryCreateCalls = (node, calls) => {
846
- if (isCallExpression(node) && isPropertyAccessExpression(node.expression) && isIdentifier(node.expression.expression) && node.expression.expression.text === NEST_FACTORY_LOCAL_NAME && node.expression.name.text === NEST_FACTORY_CREATE_METHOD_NAME) calls.push(node);
847
- node.forEachChild((child) => {
848
- collectNestFactoryCreateCalls(child, calls);
849
- });
850
- };
851
- var findRootModuleClassName = (sourceFile) => {
852
- const nestFactoryImportSource = findImportSource(sourceFile, NEST_FACTORY_LOCAL_NAME);
853
- if (nestFactoryImportSource === void 0 || nestFactoryImportSource.moduleSpecifierText !== NEST_CORE_MODULE_SPECIFIER) return;
854
- const calls = [];
855
- collectNestFactoryCreateCalls(sourceFile, calls);
856
- if (calls.length !== 1) return;
857
- const [call] = calls;
858
- if (call === void 0) return;
859
- const [moduleArgument] = call.arguments;
860
- return moduleArgument !== void 0 && isIdentifier(moduleArgument) ? moduleArgument.text : void 0;
861
- };
862
- var RESPONSE_BODY_CALL_NAMES = /* @__PURE__ */ new Set(["json", "send"]);
863
- var matchResponseBodyArgument = (expression) => {
864
- if (!isCallExpression(expression) || !isPropertyAccessExpression(expression.expression) || !RESPONSE_BODY_CALL_NAMES.has(expression.expression.name.text) || expression.arguments.length !== 1) return;
865
- const [argument] = expression.arguments;
866
- return argument;
867
- };
868
- var resolveCatchMethodBody = (catchMethod) => {
869
- const [exceptionParameter] = catchMethod.parameters;
870
- if (exceptionParameter === void 0 || !isIdentifier(exceptionParameter.name)) return;
871
- const body = catchMethod.body;
872
- if (body === void 0) return;
873
- const localDeclarations = /* @__PURE__ */ new Map();
874
- let responseBodyArgument;
875
- let sawResponseCall = false;
876
- let sawTrailingReturn = false;
877
- for (const statement of body.statements) {
878
- if (sawTrailingReturn) return;
879
- if (!sawResponseCall && isVariableStatement(statement)) {
880
- for (const declaration of statement.declarationList.declarations) {
881
- if (!isIdentifier(declaration.name) || declaration.initializer === void 0) return;
882
- localDeclarations.set(declaration.name.text, declaration.initializer);
883
- }
884
- continue;
885
- }
886
- if (!sawResponseCall && isExpressionStatement(statement)) {
887
- const argument = matchResponseBodyArgument(statement.expression);
888
- if (argument === void 0) return;
889
- responseBodyArgument = argument;
890
- sawResponseCall = true;
891
- continue;
892
- }
893
- if (sawResponseCall && isReturnStatement(statement) && statement.expression === void 0) {
894
- sawTrailingReturn = true;
895
- continue;
896
- }
897
- return;
898
- }
899
- if (!sawResponseCall || responseBodyArgument === void 0) return;
900
- return {
901
- exceptionParameterName: exceptionParameter.name.text,
902
- localDeclarations,
903
- responseBodyArgument
904
- };
905
- };
906
- var EXCEPTION_MESSAGE_MEMBER_NAME = "message";
907
- var EXCEPTION_STATUS_METHOD_NAME = "getStatus";
908
- var resolvesToExceptionParameter = (expression, exceptionParameterName, localDeclarations, visited) => {
909
- if (!isIdentifier(expression)) return false;
910
- if (expression.text === exceptionParameterName) return true;
911
- if (visited.has(expression.text)) return false;
912
- visited.add(expression.text);
913
- const aliasedExpression = localDeclarations.get(expression.text);
914
- return aliasedExpression !== void 0 ? resolvesToExceptionParameter(aliasedExpression, exceptionParameterName, localDeclarations, visited) : false;
915
- };
916
- var synthesizeErrorValueType = (expression, exceptionParameterName, localDeclarations) => {
917
- if (isPropertyAccessExpression(expression) && expression.name.text === EXCEPTION_MESSAGE_MEMBER_NAME && resolvesToExceptionParameter(expression.expression, exceptionParameterName, localDeclarations, /* @__PURE__ */ new Set())) return "string";
918
- if (isCallExpression(expression) && expression.arguments.length === 0 && isPropertyAccessExpression(expression.expression) && expression.expression.name.text === EXCEPTION_STATUS_METHOD_NAME && resolvesToExceptionParameter(expression.expression.expression, exceptionParameterName, localDeclarations, /* @__PURE__ */ new Set())) return "number";
919
- if (isObjectLiteralExpression(expression)) {
920
- const memberTypes = [];
921
- for (const property of expression.properties) {
922
- if (!isPropertyAssignment(property) || !(isIdentifier(property.name) || isStringLiteral(property.name))) return;
923
- const valueType = synthesizeErrorValueType(property.initializer, exceptionParameterName, localDeclarations);
924
- if (valueType === void 0) return;
925
- memberTypes.push(`${property.name.text}: ${valueType}`);
926
- }
927
- return `{ ${memberTypes.join("; ")} }`;
928
- }
929
- if (isStringLiteral(expression)) return "string";
930
- if (isNumericLiteral(expression)) return "number";
931
- if (isTrueLiteral(expression) || isFalseLiteral(expression)) return "boolean";
932
- if (isNullLiteral(expression)) return "null";
933
- if (isIdentifier(expression)) {
934
- const aliasedExpression = localDeclarations.get(expression.text);
935
- return aliasedExpression !== void 0 ? synthesizeErrorValueType(aliasedExpression, exceptionParameterName, localDeclarations) : void 0;
936
- }
937
- };
938
- var synthesizeErrorBodyType = (objectLiteral, exceptionParameterName, localDeclarations) => synthesizeErrorValueType(objectLiteral, exceptionParameterName, localDeclarations);
939
- var CATCH_DECORATOR_NAME = "Catch";
940
- var CATCH_METHOD_NAME = "catch";
941
- var findCatchMethod = (members) => members.find((member) => isMethodDeclaration(member) && isIdentifier(member.name) && member.name.text === CATCH_METHOD_NAME);
942
- var resolveViaGlobalFilters = (bootstrapSourceFile, bootstrapFilePath) => {
943
- const filterClassName = findGlobalFilterClassName(bootstrapSourceFile);
944
- return filterClassName === void 0 ? void 0 : resolveClassDeclaration(filterClassName, bootstrapSourceFile, bootstrapFilePath);
945
- };
946
- var resolveViaAppFilterProvider = (bootstrapSourceFile, bootstrapFilePath) => {
947
- const rootModuleClassName = findRootModuleClassName(bootstrapSourceFile);
948
- if (rootModuleClassName === void 0) return;
949
- const resolvedModule = resolveClassDeclaration(rootModuleClassName, bootstrapSourceFile, bootstrapFilePath);
950
- if (resolvedModule === void 0) return;
951
- const filterClassName = findAppFilterProviderClassName(resolvedModule.classDeclaration, resolvedModule.sourceFile);
952
- return filterClassName === void 0 ? void 0 : resolveClassDeclaration(filterClassName, resolvedModule.sourceFile, resolvedModule.filePath);
953
- };
954
- var isSameDeclaration = (a, b) => a.filePath === b.filePath && a.classDeclaration.name?.text === b.classDeclaration.name?.text;
955
- var reconcileResolvedFilter = (viaGlobalFilters, viaAppFilterProvider) => {
956
- if (viaGlobalFilters !== void 0 && viaAppFilterProvider !== void 0) return isSameDeclaration(viaGlobalFilters, viaAppFilterProvider) ? viaGlobalFilters : void 0;
957
- return viaGlobalFilters ?? viaAppFilterProvider;
958
- };
959
- var detectErrorResponseShape = (bootstrapFilePath) => {
960
- const bootstrapSourceFile = parseSourceFile(bootstrapFilePath);
961
- const resolved = reconcileResolvedFilter(resolveViaGlobalFilters(bootstrapSourceFile, bootstrapFilePath), resolveViaAppFilterProvider(bootstrapSourceFile, bootstrapFilePath));
962
- if (resolved === void 0 || findDecorator(resolved.classDeclaration, CATCH_DECORATOR_NAME) === void 0) return;
963
- const catchMethod = findCatchMethod(resolved.classDeclaration.members);
964
- if (catchMethod?.body === void 0) return;
965
- const bodyResolution = resolveCatchMethodBody(catchMethod);
966
- if (bodyResolution === void 0 || !isObjectLiteralExpression(bodyResolution.responseBodyArgument)) return;
967
- const errorBodyTypeSource = synthesizeErrorBodyType(bodyResolution.responseBodyArgument, bodyResolution.exceptionParameterName, bodyResolution.localDeclarations);
968
- return errorBodyTypeSource === void 0 ? void 0 : { errorBodyTypeSource };
969
- };
970
- var USE_GLOBAL_INTERCEPTORS_METHOD_NAME = "useGlobalInterceptors";
971
- var collectUseGlobalInterceptorsCalls = (node, calls) => {
972
- if (isCallExpression(node) && isPropertyAccessExpression(node.expression) && node.expression.name.text === USE_GLOBAL_INTERCEPTORS_METHOD_NAME) calls.push(node);
973
- node.forEachChild((child) => {
974
- collectUseGlobalInterceptorsCalls(child, calls);
975
- });
976
- };
977
- /**
978
- * Returned in registration order: `useGlobalInterceptors` concatenates onto a
979
- * single global list, so a later call (or a later argument within one call)
980
- * always registers an interceptor that wraps closer to the raw handler result.
981
- */
982
- var findGlobalInterceptorClassNames = (sourceFile) => {
983
- const calls = [];
984
- collectUseGlobalInterceptorsCalls(sourceFile, calls);
985
- if (calls.length === 0) return;
986
- const classNames = [];
987
- for (const call of calls) for (const argument of call.arguments) {
988
- if (!isNewExpression(argument) || !isIdentifier(argument.expression)) return;
989
- classNames.push(argument.expression.text);
990
- }
991
- return classNames.length === 0 ? void 0 : classNames;
992
- };
993
- var synthesizeExpressionType = (expression, parameterName, substitution, state) => {
994
- if (isIdentifier(expression) && expression.text === parameterName) {
995
- state.substitutionCount += 1;
996
- return substitution;
997
- }
998
- if (isObjectLiteralExpression(expression)) {
999
- const memberTypes = [];
1000
- for (const property of expression.properties) {
1001
- if (!isPropertyAssignment(property) || !(isIdentifier(property.name) || isStringLiteral(property.name))) return;
1002
- const valueType = synthesizeExpressionType(property.initializer, parameterName, substitution, state);
1003
- if (valueType === void 0) return;
1004
- memberTypes.push(`${property.name.text}: ${valueType}`);
1005
- }
1006
- return `{ ${memberTypes.join("; ")} }`;
1007
- }
1008
- if (isStringLiteral(expression)) return "string";
1009
- if (isNumericLiteral(expression)) return "number";
1010
- if (isTrueLiteral(expression) || isFalseLiteral(expression)) return "boolean";
1011
- if (isNullLiteral(expression)) return "null";
1012
- };
1013
- var synthesizeGenericObjectType = (objectLiteral, parameterName, substitution) => {
1014
- const state = { substitutionCount: 0 };
1015
- const objectType = synthesizeExpressionType(objectLiteral, parameterName, substitution, state);
1016
- return objectType !== void 0 && state.substitutionCount === 1 ? objectType : void 0;
1017
- };
1018
- var INTERCEPT_METHOD_NAME = "intercept";
1019
- var PIPE_MEMBER_NAME = "pipe";
1020
- var MAP_OPERATOR_NAME = "map";
1021
- var RXJS_MODULE_SPECIFIER = "rxjs";
1022
- var WRAPPED_RESULT_SUBSTITUTION = "Awaited<Result>";
1023
- var unwrapParenthesizedExpression = (expression) => {
1024
- let unwrapped = expression;
1025
- while (isParenthesizedExpression(unwrapped)) unwrapped = unwrapped.expression;
1026
- return unwrapped;
1027
- };
1028
- var resolveSoleReturnExpression = (body) => {
1029
- if (!isBlock(body)) return unwrapParenthesizedExpression(body);
1030
- const localDeclarations = /* @__PURE__ */ new Map();
1031
- let returnExpression;
1032
- let sawReturn = false;
1033
- for (const statement of body.statements) {
1034
- if (sawReturn) return;
1035
- if (isVariableStatement(statement)) {
1036
- for (const declaration of statement.declarationList.declarations) {
1037
- if (!isIdentifier(declaration.name) || declaration.initializer === void 0) return;
1038
- localDeclarations.set(declaration.name.text, declaration.initializer);
1039
- }
1040
- continue;
1041
- }
1042
- if (isReturnStatement(statement)) {
1043
- sawReturn = true;
1044
- returnExpression = statement.expression;
1045
- continue;
1046
- }
1047
- return;
1048
- }
1049
- if (returnExpression === void 0) return;
1050
- return isIdentifier(returnExpression) ? localDeclarations.get(returnExpression.text) : returnExpression;
1051
- };
1052
- var matchPipedMapCallback = (expression, interceptorSourceFile) => {
1053
- if (!isCallExpression(expression) || !isPropertyAccessExpression(expression.expression) || expression.expression.name.text !== PIPE_MEMBER_NAME || expression.arguments.length !== 1) return;
1054
- const [operator] = expression.arguments;
1055
- if (operator === void 0 || !isCallExpression(operator) || !isIdentifier(operator.expression) || operator.expression.text !== MAP_OPERATOR_NAME || operator.arguments.length !== 1) return;
1056
- const mapImportSource = findImportSource(interceptorSourceFile, operator.expression.text);
1057
- if (mapImportSource === void 0 || mapImportSource.moduleSpecifierText !== RXJS_MODULE_SPECIFIER) return;
1058
- const [callback] = operator.arguments;
1059
- return callback !== void 0 && (isArrowFunction(callback) || isFunctionExpression(callback)) ? callback : void 0;
1060
- };
1061
- var findInterceptMethod = (members) => members.find((member) => isMethodDeclaration(member) && isIdentifier(member.name) && member.name.text === INTERCEPT_METHOD_NAME);
1062
- var synthesizeInterceptorWrapperType = (interceptorClassName, bootstrapSourceFile, bootstrapFilePath, innerTypeSource) => {
1063
- const resolved = resolveClassDeclaration(interceptorClassName, bootstrapSourceFile, bootstrapFilePath);
1064
- if (resolved === void 0) return;
1065
- const interceptMethod = findInterceptMethod(resolved.classDeclaration.members);
1066
- if (interceptMethod?.body === void 0) return;
1067
- const returnExpression = resolveSoleReturnExpression(interceptMethod.body);
1068
- if (returnExpression === void 0) return;
1069
- const mapCallback = matchPipedMapCallback(returnExpression, resolved.sourceFile);
1070
- if (mapCallback === void 0 || mapCallback.parameters.length !== 1) return;
1071
- const [callbackParameter] = mapCallback.parameters;
1072
- if (callbackParameter === void 0 || !isIdentifier(callbackParameter.name)) return;
1073
- const callbackReturnExpression = resolveSoleReturnExpression(mapCallback.body);
1074
- if (callbackReturnExpression === void 0 || !isObjectLiteralExpression(callbackReturnExpression)) return;
1075
- return synthesizeGenericObjectType(callbackReturnExpression, callbackParameter.name.text, innerTypeSource);
1076
- };
1077
- /**
1078
- * Interceptors registered first wrap those registered after them, so the
1079
- * composed type is built from the last-registered interceptor (closest to the
1080
- * raw handler result) outward to the first-registered one.
1081
- */
1082
- var detectResponseWrapper = (bootstrapFilePath) => {
1083
- const bootstrapSourceFile = parseSourceFile(bootstrapFilePath);
1084
- const interceptorClassNames = findGlobalInterceptorClassNames(bootstrapSourceFile);
1085
- if (interceptorClassNames === void 0) return;
1086
- let composedTypeSource = WRAPPED_RESULT_SUBSTITUTION;
1087
- for (const interceptorClassName of [...interceptorClassNames].reverse()) {
1088
- const wrapperTypeSource = synthesizeInterceptorWrapperType(interceptorClassName, bootstrapSourceFile, bootstrapFilePath, composedTypeSource);
1089
- if (wrapperTypeSource === void 0) return;
1090
- composedTypeSource = wrapperTypeSource;
1091
- }
1092
- return { wrappedResultTypeSource: composedTypeSource };
1093
- };
1094
- var REMOTE_RESULT_HELPERS = {
1095
- json: "RemoteResult",
1096
- observable: "RemoteObservableResult",
1097
- stream: "RemoteStreamResult"
1098
- };
1099
- var WRAPPED_RESULT_HELPER = "__NestBridgeWrapped";
1100
- var toPosixPath = (filePath) => filePath.replace(/\\/g, "/");
1101
- var importSpecifierFor = (sourceFile, outputFilePath) => {
1102
- if (!sourceFile.startsWith(".") && !/^[A-Za-z]:[\\/]/.test(sourceFile) && !sourceFile.startsWith("/")) return sourceFile;
1103
- const relativePath = toPosixPath(relative(dirname(outputFilePath), sourceFile));
1104
- return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
1105
- };
1106
- var stripExtension = (filePath) => {
1107
- const extension = extname(filePath);
1108
- return extension.length > 0 ? filePath.slice(0, -extension.length) : filePath;
1109
- };
1110
- var generateControllerDeclaration = (controller, outputFilePath, responseWrapper) => {
1111
- const sourceFileSpecifier = importSpecifierFor(controller.sourceFile, outputFilePath);
1112
- const importSpecifier = stripExtension(sourceFileSpecifier);
1113
- const serverAlias = `__Server${controller.name}`;
1114
- const helperNameFor = (method) => responseWrapper !== void 0 && (method.responseKind ?? "json") === "json" ? WRAPPED_RESULT_HELPER : REMOTE_RESULT_HELPERS[method.responseKind ?? "json"];
1115
- const classBody = [
1116
- " constructor();",
1117
- "",
1118
- ...controller.methods.map((method) => {
1119
- const helperName = helperNameFor(method);
1120
- return ` ${method.name}(...args: Parameters<${serverAlias}['${method.name}']>): ${helperName}<${serverAlias}['${method.name}']>;`;
1121
- })
1122
- ].join("\n");
1123
- const rawHelperNames = controller.methods.map((method) => helperNameFor(method));
1124
- const hasWrappedMethod = rawHelperNames.includes(WRAPPED_RESULT_HELPER);
1125
- const helperImports = rawHelperNames.length === 0 ? ["RemoteResult"] : Array.from(new Set(rawHelperNames.filter((name) => name !== WRAPPED_RESULT_HELPER))).sort();
1126
- const wrappedResultTypeAliasLines = responseWrapper !== void 0 && hasWrappedMethod ? [`type ${WRAPPED_RESULT_HELPER}<T> = T extends (...args: never[]) => infer Result ? Promise<${responseWrapper.wrappedResultTypeSource}> : never;`, ""] : [];
1127
- return [
1128
- `import type { ${controller.name} as ${serverAlias} } from '${importSpecifier}';`,
1129
- ...helperImports.length > 0 ? [`import type { ${helperImports.join(", ")} } from 'nestbridge';`] : [],
1130
- "",
1131
- "/**",
1132
- " * Generated by NestBridge — client-facing methods only.",
1133
- ` * @see {@link ${sourceFileSpecifier}} for the real controller implementation.`,
1134
- " */",
1135
- ...wrappedResultTypeAliasLines,
1136
- `export declare class ${controller.name} {`,
1137
- classBody,
1138
- "}",
1139
- ""
1140
- ].join("\n");
1141
- };
1142
- var ERROR_BODY_TYPE_NAME = "NestBridgeErrorBody";
1143
- var generateErrorBodyDeclaration = (errorBodyTypeSource) => [
1144
- "/**",
1145
- " * Generated by NestBridge — inferred shape of the global exception filter's response body.",
1146
- " */",
1147
- `export type ${ERROR_BODY_TYPE_NAME} = ${errorBodyTypeSource};`,
1148
- ""
1149
- ].join("\n");
1150
- var formatDiagnostic = (diagnostic) => {
1151
- const subject = diagnostic.memberName.length > 0 ? `${diagnostic.controllerName}.${diagnostic.memberName}` : diagnostic.controllerName;
1152
- const lines = [
1153
- `[NestBridge] ${diagnostic.title}`,
1154
- "",
1155
- subject,
1156
- "",
1157
- diagnostic.detail
1158
- ];
1159
- if (diagnostic.found !== void 0) lines.push("", "Found:", diagnostic.found);
1160
- if (diagnostic.expected !== void 0) lines.push("", "Expected:", diagnostic.expected);
1161
- lines.push("", `${diagnostic.filePath}:${diagnostic.line}:${diagnostic.column}`);
1162
- return lines.join("\n");
1163
- };
1164
- var generateConfigModule = (options) => {
1165
- if (options.baseURL === void 0) return "";
1166
- return [
1167
- "import { setNestBridgeBaseURL } from 'nestbridge';",
1168
- "",
1169
- `setNestBridgeBaseURL(${JSON.stringify(options.baseURL)});`,
1170
- ""
1171
- ].join("\n");
1172
- };
1173
- /**
1174
- * Must not contain a colon: webpack treats any `letter+:` prefix as a URL
1175
- * scheme and routes the request past its filesystem resolver entirely,
1176
- * bypassing the resolveId hook this virtual module relies on.
1177
- */
1178
- var CONFIG_VIRTUAL_MODULE_ID = "virtual-nestbridge-config";
1179
- var RESOLVED_CONFIG_VIRTUAL_MODULE_ID = `\0${CONFIG_VIRTUAL_MODULE_ID}`;
1180
- var mergeNamedParametersExpression = (parameters) => {
1181
- if (parameters.length === 0) return;
1182
- const whole = parameters.find((parameter) => parameter.name === void 0);
1183
- const named = parameters.filter((parameter) => parameter.name !== void 0);
1184
- const namedEntries = named.map((parameter) => `${JSON.stringify(parameter.name)}: ${parameter.parameterName}`);
1185
- if (whole === void 0) return `{ ${namedEntries.join(", ")} }`;
1186
- if (named.length === 0) return whole.parameterName;
1187
- return `{ ...${whole.parameterName}, ${namedEntries.join(", ")} }`;
1188
- };
1189
- var generateBodyExpression = (parameters) => mergeNamedParametersExpression(parameters.filter((parameter) => parameter.kind === "body"));
1190
- var generateHeadersExpression = (parameters) => {
1191
- const headerParameters = parameters.filter((parameter) => parameter.kind === "header");
1192
- if (headerParameters.length === 0) return;
1193
- return `{ ${headerParameters.map((parameter) => `${JSON.stringify(parameter.name)}: ${parameter.parameterName}`).join(", ")} }`;
1194
- };
1195
- var generateParameterList = (parameters) => [...parameters].sort((a, b) => a.index - b.index).map((parameter) => parameter.parameterName).join(", ");
1196
- var PARAM_TOKEN_PATTERN = /:([A-Za-z0-9_]+)/;
1197
- var generatePathExpression = (method) => {
1198
- const paramParameters = method.parameters.filter((parameter) => parameter.kind === "param");
1199
- const parts = method.path.split(PARAM_TOKEN_PATTERN);
1200
- const expressionParts = [];
1201
- parts.forEach((part, index) => {
1202
- if (!(index % 2 === 1)) {
1203
- if (part.length > 0) expressionParts.push(JSON.stringify(part));
1204
- return;
1205
- }
1206
- const match = paramParameters.find((parameter) => parameter.name === part);
1207
- expressionParts.push(match !== void 0 ? `encodeURIComponent(${match.parameterName})` : JSON.stringify(`:${part}`));
1208
- });
1209
- return expressionParts.length > 0 ? expressionParts.join(" + ") : "''";
1210
- };
1211
- var generateQueryExpression = (parameters) => mergeNamedParametersExpression(parameters.filter((parameter) => parameter.kind === "query"));
1212
- var generateMethod$1 = (method) => {
1213
- const requestProperties = [`method: ${JSON.stringify(method.httpMethod)}`, `path: ${generatePathExpression(method)}`];
1214
- const queryExpression = generateQueryExpression(method.parameters);
1215
- if (queryExpression !== void 0) requestProperties.push(`query: ${queryExpression}`);
1216
- const bodyExpression = generateBodyExpression(method.parameters);
1217
- if (bodyExpression !== void 0) requestProperties.push(`body: ${bodyExpression}`);
1218
- const headersExpression = generateHeadersExpression(method.parameters);
1219
- if (headersExpression !== void 0) requestProperties.push(`headers: ${headersExpression}`);
1220
- if (method.responseKind === "stream") requestProperties.push(`responseType: "blob"`);
1221
- return [
1222
- ` ${method.name}(${generateParameterList(method.parameters)}) {`,
1223
- " return request({",
1224
- ...requestProperties.map((property) => ` ${property},`),
1225
- " });",
1226
- " }"
1227
- ].join("\n");
1228
- };
1229
- var generateControllerModule = (controller) => {
1230
- const methods = controller.methods.map(generateMethod$1).join("\n\n");
1231
- return [
1232
- `import '${CONFIG_VIRTUAL_MODULE_ID}';`,
1233
- "import { request } from 'nestbridge';",
1234
- "",
1235
- `export class ${controller.name} {`,
1236
- " constructor() {}",
1237
- "",
1238
- methods,
1239
- "}",
1240
- ""
1241
- ].join("\n");
1242
- };
1243
- var capitalize = (value) => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
1244
- var renderSelectionSet = (fields) => {
1245
- return `{ ${fields.map((field) => field.children === void 0 ? field.name : `${field.name} ${renderSelectionSet(field.children)}`).join(" ")} }`;
1246
- };
1247
- var generateGraphqlDocument = (method) => {
1248
- const variableDeclarations = method.arguments.map((argument) => `$${argument.name}: ${argument.graphqlType}`).join(", ");
1249
- const fieldArguments = method.arguments.map((argument) => `${argument.name}: $${argument.name}`).join(", ");
1250
- const variablesClause = variableDeclarations.length > 0 ? `(${variableDeclarations})` : "";
1251
- const fieldArgumentsClause = fieldArguments.length > 0 ? `(${fieldArguments})` : "";
1252
- const fieldSelection = method.selection.length > 0 ? ` ${renderSelectionSet(method.selection)}` : "";
1253
- return `${method.operationKind} ${capitalize(method.name)}${variablesClause} { ${method.operationName}${fieldArgumentsClause}${fieldSelection} }`;
1254
- };
1255
- var generateResolverArgumentList = (resolverArguments) => [...resolverArguments].sort((a, b) => a.index - b.index).map((argument) => argument.parameterName).join(", ");
1256
- var generateVariablesExpression = (resolverArguments) => {
1257
- if (resolverArguments.length === 0) return;
1258
- return `{ ${resolverArguments.map((argument) => `${JSON.stringify(argument.name)}: ${argument.parameterName}`).join(", ")} }`;
1259
- };
1260
- var generateMethod = (method) => {
1261
- const requestProperties = [`document: ${JSON.stringify(generateGraphqlDocument(method))}`];
1262
- const variablesExpression = generateVariablesExpression(method.arguments);
1263
- if (variablesExpression !== void 0) requestProperties.push(`variables: ${variablesExpression}`);
1264
- return [
1265
- ` async ${method.name}(${generateResolverArgumentList(method.arguments)}) {`,
1266
- " const result = await graphqlRequest({",
1267
- ...requestProperties.map((property) => ` ${property},`),
1268
- " });",
1269
- "",
1270
- ` return result.${method.operationName};`,
1271
- " }"
1272
- ].join("\n");
1273
- };
1274
- var generateResolverModule = (resolver) => {
1275
- const methods = resolver.methods.map(generateMethod).join("\n\n");
1276
- return [
1277
- `import '${CONFIG_VIRTUAL_MODULE_ID}';`,
1278
- "import { graphqlRequest } from 'nestbridge';",
1279
- "",
1280
- `export class ${resolver.name} {`,
1281
- " constructor() {}",
1282
- "",
1283
- methods,
1284
- "}",
1285
- ""
1286
- ].join("\n");
1287
- };
1288
- var stripLeadingParentSegments = (relativePath) => {
1289
- const segments = relativePath.split(/[\\/]/);
1290
- const firstOwnedIndex = segments.findIndex((segment) => segment !== "..");
1291
- return segments.slice(firstOwnedIndex === -1 ? segments.length : firstOwnedIndex).join("/");
1292
- };
1293
- var mirroredDeclarationPath = (sourceRoot, resolvedOutputDir, controllerFilePath) => {
1294
- const mirroredPath = stripLeadingParentSegments(relative(sourceRoot, controllerFilePath)).replace(/\.ts$/, ".d.ts");
1295
- return join(resolvedOutputDir, mirroredPath);
1296
- };
1297
- var writeControllerDeclarations = (controllers, sourceRoot, resolvedOutputDir, responseWrapper) => {
1298
- for (const controller of controllers) {
1299
- const outputFilePath = mirroredDeclarationPath(sourceRoot, resolvedOutputDir, controller.sourceFile);
1300
- mkdirSync(dirname(outputFilePath), { recursive: true });
1301
- writeFileSync(outputFilePath, generateControllerDeclaration(controller, outputFilePath, responseWrapper), "utf-8");
1302
- }
1303
- };
1304
- var ERROR_BODY_DECLARATION_FILE_NAME = "nestbridge-error-body.d.ts";
1305
- var errorBodyDeclarationPath = (resolvedOutputDir) => join(resolvedOutputDir, ERROR_BODY_DECLARATION_FILE_NAME);
1306
- var writeErrorBodyDeclaration = (resolvedOutputDir, errorResponseShape) => {
1307
- const outputFilePath = errorBodyDeclarationPath(resolvedOutputDir);
1308
- if (errorResponseShape === void 0) {
1309
- rmSync(outputFilePath, { force: true });
1310
- return;
1311
- }
1312
- mkdirSync(dirname(outputFilePath), { recursive: true });
1313
- writeFileSync(outputFilePath, generateErrorBodyDeclaration(errorResponseShape.errorBodyTypeSource), "utf-8");
1314
- };
1315
- var writeResolverDeclarations = (resolvers, sourceRoot, resolvedOutputDir) => {
1316
- for (const resolver of resolvers) {
1317
- const outputFilePath = mirroredDeclarationPath(sourceRoot, resolvedOutputDir, resolver.sourceFile);
1318
- mkdirSync(dirname(outputFilePath), { recursive: true });
1319
- writeFileSync(outputFilePath, generateControllerDeclaration(resolver, outputFilePath), "utf-8");
1320
- }
1321
- };
1322
- var discoverFiles = (patterns, root, exclude) => {
1323
- const matches = globSync([...patterns], {
1324
- cwd: root,
1325
- exclude
1326
- });
1327
- return [...new Set(matches.map((match) => resolve(root, match)))].sort();
1328
- };
1329
- var BOOTSTRAP_FILE_PATTERN = "**/main.ts";
1330
- var discoverBootstrapFile = (root, resolvedOutputDir) => {
1331
- const isExcluded = (filePath) => {
1332
- if (filePath.split(/[\\/]/).includes("node_modules")) return true;
1333
- const resolvedPath = resolve(root, filePath);
1334
- return resolvedPath === resolvedOutputDir || resolvedPath.startsWith(`${resolvedOutputDir}${sep}`);
1335
- };
1336
- const matches = discoverFiles([BOOTSTRAP_FILE_PATTERN], root, isExcluded);
1337
- return matches.length === 1 ? matches[0] : void 0;
1338
- };
1339
- var resolveNestBridgeOptions = (options) => ({
1340
- controllers: Array.isArray(options.controllers) ? options.controllers : [options.controllers],
1341
- resolvers: options.resolvers === void 0 ? [] : Array.isArray(options.resolvers) ? options.resolvers : [options.resolvers],
1342
- baseURL: options.baseURL,
1343
- debug: options.debug ?? false,
1344
- outputDir: options.outputDir ?? ".nestbridge",
1345
- root: options.root
1346
- });
1347
- var isWindows = process.platform === "win32";
1348
- var normalizePath = (filePath) => posix.normalize(isWindows ? filePath.replaceAll("\\", "/") : filePath);
1349
- var createControllerRegistry = (patterns, root) => {
1350
- const controllersByFile = /* @__PURE__ */ new Map();
1351
- const refresh = () => {
1352
- controllersByFile.clear();
1353
- const { controllers, diagnostics } = analyzeControllers(discoverFiles(patterns, root));
1354
- for (const controller of controllers) controllersByFile.set(normalizePath(controller.sourceFile), controller);
1355
- return {
1356
- controllers,
1357
- diagnostics
1358
- };
1359
- };
1360
- return {
1361
- refresh,
1362
- get: (filePath) => controllersByFile.get(filePath),
1363
- has: (filePath) => controllersByFile.has(filePath),
1364
- all: () => [...controllersByFile.values()]
1365
- };
1366
- };
1367
- var createResolverRegistry = (patterns, root) => {
1368
- const resolversByFile = /* @__PURE__ */ new Map();
1369
- const refresh = () => {
1370
- resolversByFile.clear();
1371
- const { resolvers, diagnostics } = analyzeResolvers(discoverFiles(patterns, root));
1372
- for (const resolver of resolvers) resolversByFile.set(normalizePath(resolver.sourceFile), resolver);
1373
- return {
1374
- resolvers,
1375
- diagnostics
1376
- };
1377
- };
1378
- return {
1379
- refresh,
1380
- get: (filePath) => resolversByFile.get(filePath),
1381
- has: (filePath) => resolversByFile.has(filePath),
1382
- all: () => [...resolversByFile.values()]
1383
- };
1384
- };
1385
- var reportDiagnostics = (diagnostics, watchMode) => {
1386
- for (const diagnostic of diagnostics) {
1387
- const message = formatDiagnostic(diagnostic);
1388
- if (watchMode === false) throw new Error(message);
1389
- console.warn(message);
1390
- }
1391
- };
1392
- var nestBridgeUnplugin = createUnplugin((options, meta) => {
1393
- const resolvedOptions = resolveNestBridgeOptions(options);
1394
- let root = resolvedOptions.root ?? process.cwd();
1395
- let bundlerRoot = root;
1396
- let controllerRegistry;
1397
- let resolverRegistry;
1398
- let bootstrapFilePath;
1399
- const log = (message) => {
1400
- if (resolvedOptions.debug) console.log(`[nestbridge] ${message}`);
1401
- };
1402
- const runAnalysis = () => {
1403
- const { controllers, diagnostics: controllerDiagnostics } = controllerRegistry.refresh();
1404
- const { resolvers, diagnostics: resolverDiagnostics } = resolverRegistry.refresh();
1405
- reportDiagnostics([...controllerDiagnostics, ...resolverDiagnostics], meta.watchMode);
1406
- const resolvedOutputDir = resolve(bundlerRoot, resolvedOptions.outputDir);
1407
- const discoveredBootstrapFile = discoverBootstrapFile(root, resolvedOutputDir);
1408
- bootstrapFilePath = discoveredBootstrapFile !== void 0 ? normalizePath(discoveredBootstrapFile) : void 0;
1409
- const responseWrapper = discoveredBootstrapFile !== void 0 ? detectResponseWrapper(discoveredBootstrapFile) : void 0;
1410
- const errorResponseShape = discoveredBootstrapFile !== void 0 ? detectErrorResponseShape(discoveredBootstrapFile) : void 0;
1411
- writeControllerDeclarations(controllers, root, resolvedOutputDir, responseWrapper);
1412
- writeResolverDeclarations(resolvers, root, resolvedOutputDir);
1413
- writeErrorBodyDeclaration(resolvedOutputDir, errorResponseShape);
1414
- log(`analyzed ${controllers.length} controller(s), ${resolvers.length} resolver(s), ${controllerDiagnostics.length + resolverDiagnostics.length} diagnostic(s)`);
1415
- };
1416
- return {
1417
- name: "nestbridge",
1418
- enforce: "pre",
1419
- buildStart() {
1420
- controllerRegistry = createControllerRegistry(resolvedOptions.controllers, root);
1421
- resolverRegistry = createResolverRegistry(resolvedOptions.resolvers, root);
1422
- runAnalysis();
1423
- },
1424
- resolveId(source) {
1425
- if (source === "virtual-nestbridge-config") return RESOLVED_CONFIG_VIRTUAL_MODULE_ID;
1426
- return null;
1427
- },
1428
- load(id) {
1429
- if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) return generateConfigModule(resolvedOptions);
1430
- return null;
1431
- },
1432
- transform(_code, id) {
1433
- const absolutePath = normalizePath(id);
1434
- const controller = controllerRegistry.get(absolutePath);
1435
- if (controller !== void 0) return generateControllerModule(controller);
1436
- const resolver = resolverRegistry.get(absolutePath);
1437
- if (resolver !== void 0) return generateResolverModule(resolver);
1438
- return null;
1439
- },
1440
- watchChange(id) {
1441
- const changedFile = normalizePath(id);
1442
- const wasTracked = controllerRegistry.has(changedFile) || resolverRegistry.has(changedFile) || changedFile === bootstrapFilePath;
1443
- const discoveredBootstrapFile = discoverBootstrapFile(root, resolve(bundlerRoot, resolvedOptions.outputDir));
1444
- const isTrackedNow = discoverFiles(resolvedOptions.controllers, root).map(normalizePath).includes(changedFile) || discoverFiles(resolvedOptions.resolvers, root).map(normalizePath).includes(changedFile) || discoveredBootstrapFile !== void 0 && normalizePath(discoveredBootstrapFile) === changedFile;
1445
- if (!wasTracked && !isTrackedNow) return;
1446
- runAnalysis();
1447
- log(`nestbridge source changed: ${changedFile}`);
1448
- },
1449
- vite: { configResolved(config) {
1450
- if (resolvedOptions.root === void 0) root = config.root;
1451
- bundlerRoot = config.root;
1452
- } },
1453
- webpack(compiler) {
1454
- bundlerRoot = compiler.options.context ?? bundlerRoot;
1455
- }
1456
- };
1457
- });
1
+ import { nestBridgeUnplugin } from "@nestbridge/unplugin";
1458
2
  //#endregion
1459
3
  //#region src/version.ts
1460
- var VERSION = "2.1.2";
4
+ var VERSION = "2.1.4";
1461
5
  //#endregion
1462
6
  //#region src/main.ts
1463
7
  var nestBridge = nestBridgeUnplugin.webpack;