@donkeylabs/cli 2.0.20 → 2.0.21

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": "@donkeylabs/cli",
3
- "version": "2.0.20",
3
+ "version": "2.0.21",
4
4
  "type": "module",
5
5
  "description": "CLI for @donkeylabs/server - project scaffolding and code generation",
6
6
  "main": "./src/index.ts",
@@ -70,19 +70,182 @@ async function extractMiddlewareNames(pluginPath: string): Promise<string[]> {
70
70
  try {
71
71
  const content = await readFile(pluginPath, "utf-8");
72
72
 
73
+ const names = new Set<string>();
74
+
73
75
  // Look for middleware definitions: `name: createMiddleware(...)`
74
- // This works for both old `middleware: { timing: createMiddleware(...) }`
75
- // and new `middleware: (ctx) => ({ timing: createMiddleware(...) })`
76
- const middlewareNames = [...content.matchAll(/(\w+)\s*:\s*createMiddleware\s*\(/g)]
77
- .map((m) => m[1])
78
- .filter((name): name is string => !!name);
76
+ // Supports generic config: `name: createMiddleware<Config>(...)`
77
+ for (const match of content.matchAll(/(\w+)\s*:\s*createMiddleware\s*(?:<[^>]+>)?\s*\(/g)) {
78
+ if (match[1]) names.add(match[1]);
79
+ }
80
+
81
+ // Look for direct middleware objects: `middleware: { ... }`
82
+ for (const match of content.matchAll(/middleware\s*:\s*\{/g)) {
83
+ const openBracePos = (match.index ?? 0) + match[0].length - 1;
84
+ const block = extractBalancedBlock(content, openBracePos, "{", "}");
85
+ for (const key of extractTopLevelObjectKeys(block)) {
86
+ names.add(key);
87
+ }
88
+ }
89
+
90
+ // Look for middleware factory returning object literal directly:
91
+ // `middleware: (ctx, service) => ({ ... })`
92
+ for (const match of content.matchAll(/middleware\s*:\s*\([^)]*\)\s*=>\s*\(\s*\{/g)) {
93
+ const openBracePos = (match.index ?? 0) + match[0].length - 1;
94
+ const block = extractBalancedBlock(content, openBracePos, "{", "}");
95
+ for (const key of extractTopLevelObjectKeys(block)) {
96
+ names.add(key);
97
+ }
98
+ }
99
+
100
+ // Look for middleware factory with block body:
101
+ // `middleware: (...) => { return { ... } }`
102
+ for (const match of content.matchAll(/middleware\s*:\s*\([^)]*\)\s*=>\s*\{/g)) {
103
+ const openBracePos = (match.index ?? 0) + match[0].length - 1;
104
+ const fnBody = extractBalancedBlock(content, openBracePos, "{", "}");
105
+ if (!fnBody) continue;
106
+
107
+ const returnMatch = fnBody.match(/return\s*\{/);
108
+ if (!returnMatch || returnMatch.index === undefined) continue;
79
109
 
80
- return middlewareNames;
110
+ const returnObjStart = returnMatch.index + returnMatch[0].length - 1;
111
+ const returnObj = extractBalancedBlock(fnBody, returnObjStart, "{", "}");
112
+ for (const key of extractTopLevelObjectKeys(returnObj)) {
113
+ names.add(key);
114
+ }
115
+ }
116
+
117
+ return [...names];
81
118
  } catch {
82
119
  return [];
83
120
  }
84
121
  }
85
122
 
123
+ function extractTopLevelObjectKeys(objectBlock: string): string[] {
124
+ if (!objectBlock || !objectBlock.startsWith("{") || !objectBlock.endsWith("}")) {
125
+ return [];
126
+ }
127
+
128
+ const keys: string[] = [];
129
+ const src = objectBlock.slice(1, -1);
130
+ const len = src.length;
131
+
132
+ let i = 0;
133
+ let braceDepth = 0;
134
+ let bracketDepth = 0;
135
+ let parenDepth = 0;
136
+
137
+ const isIdentifierStart = (ch: string) => /[A-Za-z_$]/.test(ch);
138
+ const isIdentifierPart = (ch: string) => /[A-Za-z0-9_$]/.test(ch);
139
+
140
+ while (i < len) {
141
+ const ch = src[i]!;
142
+
143
+ // Skip strings
144
+ if (ch === '"' || ch === "'" || ch === "`") {
145
+ const quote = ch;
146
+ i++;
147
+ while (i < len) {
148
+ const c = src[i]!;
149
+ if (c === "\\") {
150
+ i += 2;
151
+ continue;
152
+ }
153
+ if (c === quote) {
154
+ i++;
155
+ break;
156
+ }
157
+ i++;
158
+ }
159
+ continue;
160
+ }
161
+
162
+ // Skip comments
163
+ if (ch === "/" && src[i + 1] === "/") {
164
+ i += 2;
165
+ while (i < len && src[i] !== "\n") i++;
166
+ continue;
167
+ }
168
+ if (ch === "/" && src[i + 1] === "*") {
169
+ i += 2;
170
+ while (i + 1 < len && !(src[i] === "*" && src[i + 1] === "/")) i++;
171
+ i += 2;
172
+ continue;
173
+ }
174
+
175
+ // Track nesting
176
+ if (ch === "{") {
177
+ braceDepth++;
178
+ i++;
179
+ continue;
180
+ }
181
+ if (ch === "}") {
182
+ braceDepth = Math.max(0, braceDepth - 1);
183
+ i++;
184
+ continue;
185
+ }
186
+ if (ch === "[") {
187
+ bracketDepth++;
188
+ i++;
189
+ continue;
190
+ }
191
+ if (ch === "]") {
192
+ bracketDepth = Math.max(0, bracketDepth - 1);
193
+ i++;
194
+ continue;
195
+ }
196
+ if (ch === "(") {
197
+ parenDepth++;
198
+ i++;
199
+ continue;
200
+ }
201
+ if (ch === ")") {
202
+ parenDepth = Math.max(0, parenDepth - 1);
203
+ i++;
204
+ continue;
205
+ }
206
+
207
+ // Parse top-level keys only
208
+ if (braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
209
+ // Skip whitespace and commas
210
+ if (/\s|,/.test(ch)) {
211
+ i++;
212
+ continue;
213
+ }
214
+
215
+ let key = "";
216
+ const keyStart = i;
217
+
218
+ // Identifier key: authRequired: ... or authRequired(...) { ... }
219
+ if (isIdentifierStart(ch)) {
220
+ i++;
221
+ while (i < len && isIdentifierPart(src[i]!)) i++;
222
+ key = src.slice(keyStart, i);
223
+ } else {
224
+ i++;
225
+ continue;
226
+ }
227
+
228
+ // Skip optional marker and whitespace
229
+ while (i < len && /\s/.test(src[i]!)) i++;
230
+ if (src[i] === "?") {
231
+ i++;
232
+ while (i < len && /\s/.test(src[i]!)) i++;
233
+ }
234
+
235
+ // Object property or method shorthand
236
+ if (src[i] === ":" || src[i] === "(") {
237
+ keys.push(key);
238
+ }
239
+
240
+ continue;
241
+ }
242
+
243
+ i++;
244
+ }
245
+
246
+ return keys;
247
+ }
248
+
86
249
  interface ServiceDefinitionInfo {
87
250
  name: string;
88
251
  exportName: string;
@@ -1270,4 +1433,3 @@ ${eventRegistryEntries.join("\n")}
1270
1433
 
1271
1434
  await writeFile(join(outPath, "events.ts"), content);
1272
1435
  }
1273
-