@valkyrjaio/sindri 26.1.0 → 26.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valkyrjaio/sindri",
3
- "version": "26.1.0",
3
+ "version": "26.2.0",
4
4
  "description": "The Valkyrja Sindri build tool.",
5
5
  "homepage": "https://www.valkyrja.io/sindri",
6
6
  "keywords": [
@@ -8,6 +8,13 @@
8
8
  "sindri",
9
9
  "valkyrja"
10
10
  ],
11
+ "bugs": {
12
+ "url": "https://github.com/valkyrjaio/sindri-ts/issues"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/valkyrjaio/sindri-ts.git"
17
+ },
11
18
  "license": "MIT",
12
19
  "author": {
13
20
  "name": "Melech Mizrachi",
@@ -21,7 +28,7 @@
21
28
  }
22
29
  },
23
30
  "bin": {
24
- "sindri": "dist/bin/sindri.js"
31
+ "sindri": "dist/bin/sindri.cjs"
25
32
  },
26
33
  "files": [
27
34
  "dist",
@@ -31,10 +38,12 @@
31
38
  "node": ">=22"
32
39
  },
33
40
  "dependencies": {
34
- "@valkyrjaio/valkyrja": "^26.1.0",
41
+ "@valkyrjaio/valkyrja": "^26.2.0",
35
42
  "ts-morph": "^28.0.0"
36
43
  },
37
44
  "scripts": {
45
+ "build": "esbuild bin/sindri.ts --bundle --platform=node --format=cjs --outfile=dist/bin/sindri.cjs --banner:js='#!/usr/bin/env node'",
46
+ "prepublishOnly": "npm run build",
38
47
  "typescript": "cd .github/ci/typescript && npm run check",
39
48
  "typescript-outdated-check": "cd .github/ci/typescript && npm install && npm outdated",
40
49
  "typescript-outdated-check-major-release": "cd .github/ci/typescript && npm install && npm outdated",
@@ -59,5 +68,8 @@
59
68
  "root-and-suggested-outdated-check": "cd .github/ci/root-and-suggested && npm install && npm outdated",
60
69
  "root-and-suggested-outdated-check-major-release": "cd .github/ci/root-and-suggested && npm install && npm outdated",
61
70
  "root-and-suggested-npm-update": "cd .github/ci/root-and-suggested && npm update"
71
+ },
72
+ "devDependencies": {
73
+ "esbuild": "^0.28.1"
62
74
  }
63
75
  }
@@ -627,7 +627,7 @@ export abstract class AstReader {
627
627
 
628
628
  const fqn = fqnColonCase.substring(0, pos);
629
629
  const caseName = fqnColonCase.substring(pos + 2);
630
- const className = fqn.split('\\').pop() ?? fqn;
630
+ const className = fqn.slice(fqn.lastIndexOf('\\') + 1);
631
631
 
632
632
  return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(className), caseName);
633
633
  }
@@ -636,7 +636,7 @@ export abstract class AstReader {
636
636
  * Build a `ClassName.methodName` property access from a HandlerData.
637
637
  */
638
638
  protected buildHandlerExpr(handler: HandlerData): ts.PropertyAccessExpression {
639
- const className = handler.class.split('\\').pop() ?? handler.class;
639
+ const className = handler.class.slice(handler.class.lastIndexOf('\\') + 1);
640
640
 
641
641
  return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(className), handler.method);
642
642
  }
@@ -647,7 +647,7 @@ export abstract class AstReader {
647
647
  }
648
648
 
649
649
  protected buildNewExpr(className: string, args: ts.Expression[]): ts.NewExpression {
650
- const shortName = className.split('\\').pop() ?? className;
650
+ const shortName = className.slice(className.lastIndexOf('\\') + 1);
651
651
 
652
652
  return ts.factory.createNewExpression(ts.factory.createIdentifier(shortName), undefined, args);
653
653
  }
@@ -671,7 +671,7 @@ export abstract class AstReader {
671
671
  }
672
672
 
673
673
  protected buildClassIdentifierArrayExpr(classes: readonly string[]): ts.ArrayLiteralExpression {
674
- const elements = classes.map((c) => ts.factory.createIdentifier(c.split('\\').pop() ?? c));
674
+ const elements = classes.map((c) => ts.factory.createIdentifier(c.slice(c.lastIndexOf('\\') + 1)));
675
675
  return ts.factory.createArrayLiteralExpression(elements);
676
676
  }
677
677
 
@@ -73,7 +73,7 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
73
73
  }
74
74
 
75
75
  const updatedName = this.updateName(name, method, useMap, currentFilePath, currentClass);
76
- const [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware] =
76
+ const [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, processExitingMiddleware] =
77
77
  this.updateMiddleware(
78
78
  method,
79
79
  useMap,
@@ -93,7 +93,7 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
93
93
  routeMatchedMiddleware,
94
94
  routeDispatchedMiddleware,
95
95
  throwableCaughtMiddleware,
96
- exitedMiddleware,
96
+ processExitingMiddleware,
97
97
  this.parameterReader.updateArguments(method, useMap, currentFilePath, currentClass),
98
98
  this.parameterReader.updateOptions(method, useMap, currentFilePath, currentClass),
99
99
  );
@@ -130,7 +130,7 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
130
130
  routeMatchedMiddleware: string[],
131
131
  routeDispatchedMiddleware: string[],
132
132
  throwableCaughtMiddleware: string[],
133
- exitedMiddleware: string[],
133
+ processExitingMiddleware: string[],
134
134
  ): [string[], string[], string[], string[]] {
135
135
  for (const decorator of this.findDecoratorsOnNode(method, 'Middleware', useMap, currentFilePath)) {
136
136
  const mwName = this.extractExprValue(
@@ -144,7 +144,7 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
144
144
  continue;
145
145
  }
146
146
 
147
- [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware] =
147
+ [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, processExitingMiddleware] =
148
148
  this.classifyMiddleware(
149
149
  mwName,
150
150
  useMap,
@@ -152,11 +152,11 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
152
152
  routeMatchedMiddleware,
153
153
  routeDispatchedMiddleware,
154
154
  throwableCaughtMiddleware,
155
- exitedMiddleware,
155
+ processExitingMiddleware,
156
156
  );
157
157
  }
158
158
 
159
- return [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware];
159
+ return [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, processExitingMiddleware];
160
160
  }
161
161
 
162
162
  protected classifyMiddleware(
@@ -166,7 +166,7 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
166
166
  routeMatchedMiddleware: string[],
167
167
  routeDispatchedMiddleware: string[],
168
168
  throwableCaughtMiddleware: string[],
169
- exitedMiddleware: string[],
169
+ processExitingMiddleware: string[],
170
170
  ): [string[], string[], string[], string[]] {
171
171
  if (this.classImplementsInterface(mwName, 'RouteMatchedMiddlewareContract', useMap, currentFilePath)) {
172
172
  routeMatchedMiddleware = [...routeMatchedMiddleware, mwName];
@@ -180,11 +180,11 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
180
180
  throwableCaughtMiddleware = [...throwableCaughtMiddleware, mwName];
181
181
  }
182
182
 
183
- if (this.classImplementsInterface(mwName, 'ExitedMiddlewareContract', useMap, currentFilePath)) {
184
- exitedMiddleware = [...exitedMiddleware, mwName];
183
+ if (this.classImplementsInterface(mwName, 'ProcessExitingMiddlewareContract', useMap, currentFilePath)) {
184
+ processExitingMiddleware = [...processExitingMiddleware, mwName];
185
185
  }
186
186
 
187
- return [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware];
187
+ return [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, processExitingMiddleware];
188
188
  }
189
189
 
190
190
  protected buildRouteExpr(data: CliRouteData): ts.Expression {
@@ -213,7 +213,7 @@ export class CliRouteAttributeReader extends RouteAttributeReader implements Cli
213
213
  this.buildClassArrayExpr(data.routeMatchedMiddleware),
214
214
  this.buildClassArrayExpr(data.routeDispatchedMiddleware),
215
215
  this.buildClassArrayExpr(data.throwableCaughtMiddleware),
216
- this.buildClassArrayExpr(data.exitedMiddleware),
216
+ this.buildClassArrayExpr(data.processExitingMiddleware),
217
217
  ];
218
218
  }
219
219
  }
@@ -65,7 +65,7 @@ export class ConfigReader extends AstReader implements ConfigReaderContract {
65
65
  if (ts.isExpressionStatement(stmt) && ts.isCallExpression(stmt.expression)) {
66
66
  const call = stmt.expression;
67
67
 
68
- if (ts.isIdentifier(call.expression) && call.expression.text === 'super') {
68
+ if (call.expression.kind === ts.SyntaxKind.SuperKeyword) {
69
69
  return call.arguments;
70
70
  }
71
71
  }
@@ -133,13 +133,14 @@ export class ConfigReader extends AstReader implements ConfigReaderContract {
133
133
  return arg.text;
134
134
  }
135
135
 
136
- // process.cwd() → use the file directory as a proxy
136
+ // process.cwd() resolves to the current working directory, which is the application root
137
+ // that sindri is run from (the same directory the application itself runs from).
137
138
  if (ts.isCallExpression(arg) && ts.isPropertyAccessExpression(arg.expression)) {
138
139
  const obj = arg.expression.expression;
139
140
  const prop = arg.expression.name;
140
141
 
141
142
  if (ts.isIdentifier(obj) && obj.text === 'process' && ts.isIdentifier(prop) && prop.text === 'cwd') {
142
- return fileDir;
143
+ return process.cwd();
143
144
  }
144
145
  }
145
146
 
@@ -150,9 +151,8 @@ export class ConfigReader extends AstReader implements ConfigReaderContract {
150
151
 
151
152
  if (
152
153
  ts.isPropertyAccessExpression(arg) &&
153
- ts.isPropertyAccessExpression(arg.expression) &&
154
- ts.isMetaProperty(arg.expression.expression) &&
155
- arg.expression.expression.name.text === 'meta'
154
+ ts.isMetaProperty(arg.expression) &&
155
+ arg.expression.name.text === 'meta'
156
156
  ) {
157
157
  return fileDir;
158
158
  }
@@ -38,7 +38,7 @@ export interface HttpRouteMiddlewareReaderContract {
38
38
  routeDispatchedMiddleware: string[],
39
39
  throwableCaughtMiddleware: string[],
40
40
  sendingResponseMiddleware: string[],
41
- terminatedMiddleware: string[],
41
+ responseSentMiddleware: string[],
42
42
  ): [string[], string[], string[], string[], string[]];
43
43
 
44
44
  updateRequestStruct(
@@ -23,7 +23,7 @@ export class CliRouteData implements CliRouteDataContract {
23
23
  readonly routeMatchedMiddleware: readonly string[] = [],
24
24
  readonly routeDispatchedMiddleware: readonly string[] = [],
25
25
  readonly throwableCaughtMiddleware: readonly string[] = [],
26
- readonly exitedMiddleware: readonly string[] = [],
26
+ readonly processExitingMiddleware: readonly string[] = [],
27
27
  args: readonly CliArgumentParameterData[] = [],
28
28
  readonly options: readonly CliOptionParameterData[] = [],
29
29
  ) {
@@ -19,7 +19,7 @@ export interface CliRouteDataContract {
19
19
  readonly routeMatchedMiddleware: readonly string[];
20
20
  readonly routeDispatchedMiddleware: readonly string[];
21
21
  readonly throwableCaughtMiddleware: readonly string[];
22
- readonly exitedMiddleware: readonly string[];
22
+ readonly processExitingMiddleware: readonly string[];
23
23
  readonly arguments: readonly CliArgumentParameterDataContract[];
24
24
  readonly options: readonly CliOptionParameterDataContract[];
25
25
  }
@@ -20,7 +20,7 @@ export interface HttpRouteDataContract {
20
20
  readonly routeDispatchedMiddleware: readonly string[];
21
21
  readonly throwableCaughtMiddleware: readonly string[];
22
22
  readonly sendingResponseMiddleware: readonly string[];
23
- readonly terminatedMiddleware: readonly string[];
23
+ readonly responseSentMiddleware: readonly string[];
24
24
  readonly requestStruct: string | null;
25
25
  readonly responseStruct: string | null;
26
26
  readonly isDynamic: boolean;
@@ -21,7 +21,7 @@ export class HttpRouteData implements HttpRouteDataContract {
21
21
  readonly routeDispatchedMiddleware: readonly string[] = [],
22
22
  readonly throwableCaughtMiddleware: readonly string[] = [],
23
23
  readonly sendingResponseMiddleware: readonly string[] = [],
24
- readonly terminatedMiddleware: readonly string[] = [],
24
+ readonly responseSentMiddleware: readonly string[] = [],
25
25
  readonly requestStruct: string | null = null,
26
26
  readonly responseStruct: string | null = null,
27
27
  readonly isDynamic: boolean = false,
@@ -188,7 +188,7 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
188
188
  routeDispatchedMiddleware,
189
189
  throwableCaughtMiddleware,
190
190
  sendingResponseMiddleware,
191
- terminatedMiddleware,
191
+ responseSentMiddleware,
192
192
  ] = this.middlewareReader.updateMiddleware(
193
193
  method,
194
194
  useMap,
@@ -210,7 +210,7 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
210
210
  routeDispatchedMiddleware,
211
211
  throwableCaughtMiddleware,
212
212
  sendingResponseMiddleware,
213
- terminatedMiddleware,
213
+ responseSentMiddleware,
214
214
  this.middlewareReader.updateRequestStruct(method, useMap, currentFilePath, currentClass),
215
215
  this.middlewareReader.updateResponseStruct(method, useMap, currentFilePath, currentClass),
216
216
  resolvedIsDynamic,
@@ -75,7 +75,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
75
75
  routeDispatchedMiddleware: string[],
76
76
  throwableCaughtMiddleware: string[],
77
77
  sendingResponseMiddleware: string[],
78
- terminatedMiddleware: string[],
78
+ responseSentMiddleware: string[],
79
79
  ): [string[], string[], string[], string[], string[]] {
80
80
  for (const decorator of this.findDecoratorsOnNode(method, 'Middleware', useMap, namespace)) {
81
81
  const mwName = this.extractExprValue(this.getDecoratorArg(decorator, 0), useMap, namespace, currentClass);
@@ -89,7 +89,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
89
89
  routeDispatchedMiddleware,
90
90
  throwableCaughtMiddleware,
91
91
  sendingResponseMiddleware,
92
- terminatedMiddleware,
92
+ responseSentMiddleware,
93
93
  ] = this.classifyMiddleware(
94
94
  mwName,
95
95
  useMap,
@@ -98,7 +98,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
98
98
  routeDispatchedMiddleware,
99
99
  throwableCaughtMiddleware,
100
100
  sendingResponseMiddleware,
101
- terminatedMiddleware,
101
+ responseSentMiddleware,
102
102
  );
103
103
  }
104
104
 
@@ -107,7 +107,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
107
107
  routeDispatchedMiddleware,
108
108
  throwableCaughtMiddleware,
109
109
  sendingResponseMiddleware,
110
- terminatedMiddleware,
110
+ responseSentMiddleware,
111
111
  ];
112
112
  }
113
113
 
@@ -151,7 +151,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
151
151
  this.buildClassIdentifierArrayExpr(data.routeDispatchedMiddleware),
152
152
  this.buildClassIdentifierArrayExpr(data.throwableCaughtMiddleware),
153
153
  this.buildClassIdentifierArrayExpr(data.sendingResponseMiddleware),
154
- this.buildClassIdentifierArrayExpr(data.terminatedMiddleware),
154
+ this.buildClassIdentifierArrayExpr(data.responseSentMiddleware),
155
155
  ];
156
156
  }
157
157
 
@@ -181,7 +181,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
181
181
  routeDispatchedMiddleware: string[],
182
182
  throwableCaughtMiddleware: string[],
183
183
  sendingResponseMiddleware: string[],
184
- terminatedMiddleware: string[],
184
+ responseSentMiddleware: string[],
185
185
  ): [string[], string[], string[], string[], string[]] {
186
186
  if (this.classImplementsInterface(mwName, 'RouteMatchedMiddlewareContract', useMap, currentFilePath)) {
187
187
  routeMatchedMiddleware = [...routeMatchedMiddleware, mwName];
@@ -199,8 +199,8 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
199
199
  sendingResponseMiddleware = [...sendingResponseMiddleware, mwName];
200
200
  }
201
201
 
202
- if (this.classImplementsInterface(mwName, 'TerminatedMiddlewareContract', useMap, currentFilePath)) {
203
- terminatedMiddleware = [...terminatedMiddleware, mwName];
202
+ if (this.classImplementsInterface(mwName, 'ResponseSentMiddlewareContract', useMap, currentFilePath)) {
203
+ responseSentMiddleware = [...responseSentMiddleware, mwName];
204
204
  }
205
205
 
206
206
  return [
@@ -208,7 +208,7 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
208
208
  routeDispatchedMiddleware,
209
209
  throwableCaughtMiddleware,
210
210
  sendingResponseMiddleware,
211
- terminatedMiddleware,
211
+ responseSentMiddleware,
212
212
  ];
213
213
  }
214
214
  }
@@ -8,8 +8,8 @@
8
8
  */
9
9
 
10
10
  export class SindriInfo {
11
- static readonly VERSION = '26.1.0' as const;
12
- static readonly VERSION_BUILD_DATE_TIME = 'June 17 2026 22:16:53 MST' as const;
11
+ static readonly VERSION = '26.2.0' as const;
12
+ static readonly VERSION_BUILD_DATE_TIME = 'July 25 2026 00:19:15 MST' as const;
13
13
  static readonly ICON = `\
14
14
  ██████████
15
15
  ████ ████
@@ -189,6 +189,12 @@ export abstract class GenerateDataFromAst {
189
189
  }
190
190
 
191
191
  for (const entry of entries) {
192
+ // Never descend into dependency directories — application source never lives there,
193
+ // and a matching class name in node_modules must not shadow the real one.
194
+ if (entry.isDirectory() && entry.name === 'node_modules') {
195
+ continue;
196
+ }
197
+
192
198
  const fullPath = path.join(dir, entry.name);
193
199
 
194
200
  if (entry.isDirectory()) {
@@ -26,7 +26,7 @@ export abstract class AstFileGenerator {
26
26
 
27
27
  const fqn = fqnColonCase.substring(0, pos);
28
28
  const caseName = fqnColonCase.substring(pos + 2);
29
- const className = fqn.split('\\').pop() ?? fqn;
29
+ const className = fqn.slice(fqn.lastIndexOf('\\') + 1);
30
30
 
31
31
  return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(className), caseName);
32
32
  }
@@ -70,7 +70,7 @@ export class AstContainerDataFileGenerator extends AstFileGenerator implements C
70
70
  const keyExpr = this.buildEnumCaseExpr(serviceId);
71
71
  const printedKey = this.printer.printNode(ts.EmitHint.Unspecified, keyExpr, this.dummySourceFile);
72
72
 
73
- const shortProviderClass = providerClass.split('\\').pop() ?? providerClass;
73
+ const shortProviderClass = providerClass.slice(providerClass.lastIndexOf('\\') + 1);
74
74
 
75
75
  const formattedKey = serviceId.includes('::') ? `[${printedKey}]` : `['${printedKey}']`;
76
76