db4ai 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-3DWAMVV5.js +305 -0
- package/dist/chunk-3DWAMVV5.js.map +1 -0
- package/dist/chunk-COTPYBYM.js +618 -0
- package/dist/chunk-COTPYBYM.js.map +1 -0
- package/dist/chunk-EERD6CDF.js +735 -0
- package/dist/chunk-EERD6CDF.js.map +1 -0
- package/dist/chunk-FUF4HJTC.js +758 -0
- package/dist/chunk-FUF4HJTC.js.map +1 -0
- package/dist/chunk-JLL6FH5L.js +16 -0
- package/dist/chunk-JLL6FH5L.js.map +1 -0
- package/dist/chunk-JXFW6AIT.js +192 -0
- package/dist/chunk-JXFW6AIT.js.map +1 -0
- package/dist/chunk-XLSYCQPG.js +854 -0
- package/dist/chunk-XLSYCQPG.js.map +1 -0
- package/dist/chunk-Y5IXAS7F.js +569 -0
- package/dist/chunk-Y5IXAS7F.js.map +1 -0
- package/dist/cli/bin.d.ts +13 -12
- package/dist/cli/bin.js +277 -307
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/dashboard/index.d.ts +295 -14
- package/dist/cli/dashboard/index.js +60 -15
- package/dist/cli/dashboard/index.js.map +1 -1
- package/dist/cli/index.d.ts +10 -16
- package/dist/cli/index.js +94 -47
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/runtime/index.d.ts +52 -23
- package/dist/cli/runtime/index.js +10 -704
- package/dist/cli/runtime/index.js.map +1 -1
- package/dist/cli/scanner/index.d.ts +17 -15
- package/dist/cli/scanner/index.js +8 -639
- package/dist/cli/scanner/index.js.map +1 -1
- package/dist/cli/seed/index.d.ts +16 -12
- package/dist/cli/seed/index.js +12 -773
- package/dist/cli/seed/index.js.map +1 -1
- package/dist/cli/sync/index.d.ts +54 -53
- package/dist/cli/sync/index.js +23 -704
- package/dist/cli/sync/index.js.map +1 -1
- package/dist/cli/terminal.d.ts +9 -8
- package/dist/cli/terminal.js +6 -209
- package/dist/cli/terminal.js.map +1 -1
- package/dist/cli/workflow/index.d.ts +18 -10
- package/dist/cli/workflow/index.js +6 -307
- package/dist/cli/workflow/index.js.map +1 -1
- package/dist/handlers.d.ts +10 -9
- package/dist/handlers.js +6 -38
- package/dist/handlers.js.map +1 -1
- package/dist/index.d.ts +120 -118
- package/dist/index.js +1963 -3125
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/dist/cli/bin.d.ts.map +0 -1
- package/dist/cli/dashboard/App.d.ts +0 -16
- package/dist/cli/dashboard/App.d.ts.map +0 -1
- package/dist/cli/dashboard/App.js +0 -116
- package/dist/cli/dashboard/App.js.map +0 -1
- package/dist/cli/dashboard/components/index.d.ts +0 -70
- package/dist/cli/dashboard/components/index.d.ts.map +0 -1
- package/dist/cli/dashboard/components/index.js +0 -192
- package/dist/cli/dashboard/components/index.js.map +0 -1
- package/dist/cli/dashboard/hooks/index.d.ts +0 -76
- package/dist/cli/dashboard/hooks/index.d.ts.map +0 -1
- package/dist/cli/dashboard/hooks/index.js +0 -201
- package/dist/cli/dashboard/hooks/index.js.map +0 -1
- package/dist/cli/dashboard/index.d.ts.map +0 -1
- package/dist/cli/dashboard/types.d.ts +0 -84
- package/dist/cli/dashboard/types.d.ts.map +0 -1
- package/dist/cli/dashboard/types.js +0 -5
- package/dist/cli/dashboard/types.js.map +0 -1
- package/dist/cli/dashboard/views/index.d.ts +0 -51
- package/dist/cli/dashboard/views/index.d.ts.map +0 -1
- package/dist/cli/dashboard/views/index.js +0 -72
- package/dist/cli/dashboard/views/index.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/runtime/index.d.ts.map +0 -1
- package/dist/cli/scanner/index.d.ts.map +0 -1
- package/dist/cli/seed/index.d.ts.map +0 -1
- package/dist/cli/sync/index.d.ts.map +0 -1
- package/dist/cli/terminal.d.ts.map +0 -1
- package/dist/cli/workflow/index.d.ts.map +0 -1
- package/dist/errors.d.ts +0 -43
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -47
- package/dist/errors.js.map +0 -1
- package/dist/handlers.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -276
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -12
- package/dist/types.js.map +0 -1
|
@@ -1,640 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import traverse from '@babel/traverse';
|
|
10
|
-
import matter from 'gray-matter';
|
|
11
|
-
import { minimatch } from 'minimatch';
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// Default patterns
|
|
14
|
-
// ============================================================================
|
|
15
|
-
const DEFAULT_EXCLUDE = ['node_modules/**', 'dist/**', '**/*.test.ts', '**/*.spec.ts', 'tests/**', '__tests__/**'];
|
|
16
|
-
// ============================================================================
|
|
17
|
-
// Glob matching utilities
|
|
18
|
-
// ============================================================================
|
|
19
|
-
function matchesPatterns(filePath, patterns) {
|
|
20
|
-
// Separate positive and negative patterns
|
|
21
|
-
const positivePatterns = patterns.filter((p) => !p.startsWith('!'));
|
|
22
|
-
const negativePatterns = patterns.filter((p) => p.startsWith('!')).map((p) => p.slice(1));
|
|
23
|
-
// Must match at least one positive pattern (or have no positive patterns)
|
|
24
|
-
const matchesPositive = positivePatterns.length === 0 || positivePatterns.some((p) => minimatch(filePath, p, { dot: true }));
|
|
25
|
-
// Must not match any negative pattern
|
|
26
|
-
const matchesNegative = negativePatterns.some((p) => minimatch(filePath, p, { dot: true }));
|
|
27
|
-
return matchesPositive && !matchesNegative;
|
|
28
|
-
}
|
|
29
|
-
function shouldIncludeFile(relativePath, include, exclude) {
|
|
30
|
-
// Check include patterns if provided
|
|
31
|
-
if (include && include.length > 0) {
|
|
32
|
-
if (!matchesPatterns(relativePath, include)) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
// Check exclude patterns
|
|
37
|
-
const excludePatterns = exclude || DEFAULT_EXCLUDE;
|
|
38
|
-
if (excludePatterns.some((p) => minimatch(relativePath, p, { dot: true }))) {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
// ============================================================================
|
|
44
|
-
// File scanning
|
|
45
|
-
// ============================================================================
|
|
46
|
-
async function* walkDirectory(dir, root) {
|
|
47
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
48
|
-
for (const entry of entries) {
|
|
49
|
-
const fullPath = join(dir, entry.name);
|
|
50
|
-
const relativePath = relative(root, fullPath);
|
|
51
|
-
if (entry.isDirectory()) {
|
|
52
|
-
// Skip node_modules and hidden directories by default
|
|
53
|
-
if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
yield* walkDirectory(fullPath, root);
|
|
57
|
-
}
|
|
58
|
-
else if (entry.isFile()) {
|
|
59
|
-
yield { path: fullPath, relativePath };
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function parseTypeScript(content) {
|
|
64
|
-
try {
|
|
65
|
-
return {
|
|
66
|
-
ast: parse(content, {
|
|
67
|
-
sourceType: 'module',
|
|
68
|
-
plugins: ['typescript', 'jsx'],
|
|
69
|
-
}),
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
return {
|
|
74
|
-
ast: null,
|
|
75
|
-
error: err instanceof Error ? err.message : String(err),
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Extract a simple value from an AST node (strings, numbers, booleans, arrays, objects)
|
|
81
|
-
*/
|
|
82
|
-
function extractValue(node) {
|
|
83
|
-
if (!node)
|
|
84
|
-
return undefined;
|
|
85
|
-
switch (node.type) {
|
|
86
|
-
case 'StringLiteral':
|
|
87
|
-
return node.value;
|
|
88
|
-
case 'NumericLiteral':
|
|
89
|
-
return node.value;
|
|
90
|
-
case 'BooleanLiteral':
|
|
91
|
-
return node.value;
|
|
92
|
-
case 'NullLiteral':
|
|
93
|
-
return null;
|
|
94
|
-
case 'ArrayExpression':
|
|
95
|
-
return node.elements.map((el) => extractValue(el));
|
|
96
|
-
case 'ObjectExpression':
|
|
97
|
-
return extractObjectValue(node);
|
|
98
|
-
case 'TemplateLiteral':
|
|
99
|
-
// Simple case: no expressions
|
|
100
|
-
if (node.expressions.length === 0 && node.quasis.length === 1) {
|
|
101
|
-
return node.quasis[0].value.cooked;
|
|
102
|
-
}
|
|
103
|
-
return undefined;
|
|
104
|
-
default:
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function extractObjectValue(node) {
|
|
109
|
-
const result = {};
|
|
110
|
-
for (const prop of node.properties) {
|
|
111
|
-
if (prop.type === 'ObjectProperty') {
|
|
112
|
-
const key = prop.key.type === 'Identifier' ? prop.key.name : prop.key.type === 'StringLiteral' ? prop.key.value : null;
|
|
113
|
-
if (key) {
|
|
114
|
-
result[key] = extractValue(prop.value);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else if (prop.type === 'SpreadElement') {
|
|
118
|
-
// Can't statically analyze spreads
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return result;
|
|
123
|
-
}
|
|
124
|
-
function getImportsFromMdxai(ast) {
|
|
125
|
-
const imports = new Map();
|
|
126
|
-
traverse(ast, {
|
|
127
|
-
ImportDeclaration(path) {
|
|
128
|
-
const source = path.node.source.value;
|
|
129
|
-
if (source !== 'mdxai')
|
|
130
|
-
return;
|
|
131
|
-
for (const specifier of path.node.specifiers) {
|
|
132
|
-
if (specifier.type === 'ImportSpecifier') {
|
|
133
|
-
const importedName = specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value;
|
|
134
|
-
imports.set(specifier.local.name, {
|
|
135
|
-
localName: specifier.local.name,
|
|
136
|
-
importedName,
|
|
137
|
-
source,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
else if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
141
|
-
// import * as mdxai from 'mdxai'
|
|
142
|
-
imports.set(specifier.local.name, {
|
|
143
|
-
localName: specifier.local.name,
|
|
144
|
-
importedName: '*',
|
|
145
|
-
source,
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
return imports;
|
|
152
|
-
}
|
|
153
|
-
function isDBCall(callee, dbLocalName, namespaceImport) {
|
|
154
|
-
// Direct DB() call
|
|
155
|
-
if (callee.type === 'Identifier' && callee.name === 'DB') {
|
|
156
|
-
return dbLocalName === 'DB' || dbLocalName === null; // Allow bare DB() if no import check needed
|
|
157
|
-
}
|
|
158
|
-
// Aliased import: Database() where DB was imported as Database
|
|
159
|
-
if (callee.type === 'Identifier' && callee.name === dbLocalName) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
// Namespace import: mdxai.DB()
|
|
163
|
-
if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === namespaceImport && callee.property.type === 'Identifier' && callee.property.name === 'DB') {
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
function findDBExports(content, ast, imports, rejectNonMdxaiImports) {
|
|
169
|
-
const results = [];
|
|
170
|
-
// Track which variable declarations contain DB() calls
|
|
171
|
-
const dbVariables = new Map();
|
|
172
|
-
// Find the local name for DB (could be aliased)
|
|
173
|
-
let dbLocalName = null;
|
|
174
|
-
let namespaceImport = null;
|
|
175
|
-
let hasNonMdxaiDBImport = false;
|
|
176
|
-
for (const [localName, info] of imports) {
|
|
177
|
-
if (info.importedName === 'DB') {
|
|
178
|
-
dbLocalName = localName;
|
|
179
|
-
}
|
|
180
|
-
else if (info.importedName === '*') {
|
|
181
|
-
namespaceImport = localName;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
// Check if there's a DB import from a non-mdxai package
|
|
185
|
-
traverse(ast, {
|
|
186
|
-
ImportDeclaration(path) {
|
|
187
|
-
const source = path.node.source.value;
|
|
188
|
-
if (source !== 'mdxai') {
|
|
189
|
-
for (const specifier of path.node.specifiers) {
|
|
190
|
-
if (specifier.type === 'ImportSpecifier') {
|
|
191
|
-
const importedName = specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value;
|
|
192
|
-
if (importedName === 'DB') {
|
|
193
|
-
hasNonMdxaiDBImport = true;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
// If there's a DB import from a non-mdxai package, reject this file
|
|
201
|
-
if (rejectNonMdxaiImports && hasNonMdxaiDBImport) {
|
|
202
|
-
return [];
|
|
203
|
-
}
|
|
204
|
-
// If no explicit import, allow bare DB() calls
|
|
205
|
-
const effectiveDbName = dbLocalName || 'DB';
|
|
206
|
-
traverse(ast, {
|
|
207
|
-
// Handle: export default DB({...})
|
|
208
|
-
ExportDefaultDeclaration(path) {
|
|
209
|
-
const declaration = path.node.declaration;
|
|
210
|
-
if (declaration && declaration.type === 'CallExpression') {
|
|
211
|
-
const callee = declaration.callee;
|
|
212
|
-
if (isDBCall(callee, dbLocalName, namespaceImport) && declaration.arguments.length > 0) {
|
|
213
|
-
const arg = declaration.arguments[0];
|
|
214
|
-
if (arg.type === 'ObjectExpression') {
|
|
215
|
-
const config = extractObjectValue(arg);
|
|
216
|
-
const types = extractTypesFromConfig(config);
|
|
217
|
-
results.push({
|
|
218
|
-
exportName: 'default',
|
|
219
|
-
config,
|
|
220
|
-
types,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
// Handle: export const schema = DB({...})
|
|
227
|
-
ExportNamedDeclaration(path) {
|
|
228
|
-
const declaration = path.node.declaration;
|
|
229
|
-
if (declaration && declaration.type === 'VariableDeclaration') {
|
|
230
|
-
for (const decl of declaration.declarations) {
|
|
231
|
-
if (decl.id.type === 'Identifier' && decl.init && decl.init.type === 'CallExpression') {
|
|
232
|
-
const callee = decl.init.callee;
|
|
233
|
-
if (isDBCall(callee, dbLocalName, namespaceImport) && decl.init.arguments.length > 0) {
|
|
234
|
-
const arg = decl.init.arguments[0];
|
|
235
|
-
if (arg.type === 'ObjectExpression') {
|
|
236
|
-
const config = extractObjectValue(arg);
|
|
237
|
-
const types = extractTypesFromConfig(config);
|
|
238
|
-
results.push({
|
|
239
|
-
exportName: decl.id.name,
|
|
240
|
-
config,
|
|
241
|
-
types,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
// Handle: export { schema }
|
|
249
|
-
if (path.node.specifiers) {
|
|
250
|
-
for (const specifier of path.node.specifiers) {
|
|
251
|
-
if (specifier.type === 'ExportSpecifier') {
|
|
252
|
-
const localName = specifier.local.name;
|
|
253
|
-
if (dbVariables.has(localName)) {
|
|
254
|
-
const info = dbVariables.get(localName);
|
|
255
|
-
const exportedName = specifier.exported.type === 'Identifier' ? specifier.exported.name : specifier.exported.value;
|
|
256
|
-
results.push({
|
|
257
|
-
...info,
|
|
258
|
-
exportName: exportedName,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
// Track variable declarations that might be exported later
|
|
266
|
-
VariableDeclarator(path) {
|
|
267
|
-
if (path.node.id.type === 'Identifier' && path.node.init && path.node.init.type === 'CallExpression') {
|
|
268
|
-
const callee = path.node.init.callee;
|
|
269
|
-
if (isDBCall(callee, dbLocalName, namespaceImport) && path.node.init.arguments.length > 0) {
|
|
270
|
-
const arg = path.node.init.arguments[0];
|
|
271
|
-
if (arg.type === 'ObjectExpression') {
|
|
272
|
-
const config = extractObjectValue(arg);
|
|
273
|
-
const types = extractTypesFromConfig(config);
|
|
274
|
-
dbVariables.set(path.node.id.name, {
|
|
275
|
-
exportName: path.node.id.name,
|
|
276
|
-
config,
|
|
277
|
-
types,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
return results;
|
|
285
|
-
}
|
|
286
|
-
function extractTypesFromConfig(config) {
|
|
287
|
-
const types = [];
|
|
288
|
-
for (const key of Object.keys(config)) {
|
|
289
|
-
// Skip special keys that start with $
|
|
290
|
-
if (!key.startsWith('$')) {
|
|
291
|
-
types.push(key);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return types;
|
|
295
|
-
}
|
|
296
|
-
function extractNamespace(config) {
|
|
297
|
-
// Try $id first
|
|
298
|
-
const id = config['$id'];
|
|
299
|
-
if (typeof id === 'string') {
|
|
300
|
-
// Handle URLs like 'https://db.sb/my-namespace'
|
|
301
|
-
if (id.includes('/')) {
|
|
302
|
-
const parts = id.split('/');
|
|
303
|
-
return parts[parts.length - 1];
|
|
304
|
-
}
|
|
305
|
-
return id;
|
|
306
|
-
}
|
|
307
|
-
// Try $context
|
|
308
|
-
const context = config['$context'];
|
|
309
|
-
if (typeof context === 'string') {
|
|
310
|
-
return context;
|
|
311
|
-
}
|
|
312
|
-
return undefined;
|
|
313
|
-
}
|
|
314
|
-
async function parseSchemaFile(filePath, relativePath, content, rejectNonMdxaiImports) {
|
|
315
|
-
const parseResult = parseTypeScript(content);
|
|
316
|
-
if (!parseResult.ast) {
|
|
317
|
-
return { schemas: null, error: parseResult.error };
|
|
318
|
-
}
|
|
319
|
-
const imports = getImportsFromMdxai(parseResult.ast);
|
|
320
|
-
const dbExports = findDBExports(content, parseResult.ast, imports, rejectNonMdxaiImports);
|
|
321
|
-
if (dbExports.length === 0)
|
|
322
|
-
return { schemas: null };
|
|
323
|
-
return {
|
|
324
|
-
schemas: dbExports.map((dbExport) => ({
|
|
325
|
-
path: filePath,
|
|
326
|
-
relativePath,
|
|
327
|
-
namespace: extractNamespace(dbExport.config),
|
|
328
|
-
types: dbExport.types,
|
|
329
|
-
exportName: dbExport.exportName,
|
|
330
|
-
})),
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// Seed file parsing
|
|
335
|
-
// ============================================================================
|
|
336
|
-
function findSeedOrGenerateExports(ast) {
|
|
337
|
-
let config = null;
|
|
338
|
-
traverse(ast, {
|
|
339
|
-
ExportDefaultDeclaration(path) {
|
|
340
|
-
const declaration = path.node.declaration;
|
|
341
|
-
if (declaration && declaration.type === 'CallExpression') {
|
|
342
|
-
const callee = declaration.callee;
|
|
343
|
-
// Check for Seed(...) or Generate(...)
|
|
344
|
-
if (callee.type === 'Identifier' && (callee.name === 'Seed' || callee.name === 'Generate')) {
|
|
345
|
-
if (declaration.arguments.length > 0) {
|
|
346
|
-
const arg = declaration.arguments[0];
|
|
347
|
-
if (arg.type === 'ObjectExpression') {
|
|
348
|
-
config = extractObjectValue(arg);
|
|
349
|
-
// For Generate(), also capture the function name as a hint
|
|
350
|
-
if (callee.name === 'Generate' && config && !config.prompt) {
|
|
351
|
-
// Generate typically has a prompt, keep type from config
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
});
|
|
359
|
-
return config;
|
|
360
|
-
}
|
|
361
|
-
async function parseSeedTsFile(filePath, relativePath, content) {
|
|
362
|
-
const parseResult = parseTypeScript(content);
|
|
363
|
-
if (!parseResult.ast) {
|
|
364
|
-
return { seed: null, error: parseResult.error };
|
|
365
|
-
}
|
|
366
|
-
const config = findSeedOrGenerateExports(parseResult.ast);
|
|
367
|
-
if (!config)
|
|
368
|
-
return { seed: null };
|
|
369
|
-
return {
|
|
370
|
-
seed: {
|
|
371
|
-
path: filePath,
|
|
372
|
-
relativePath,
|
|
373
|
-
format: 'ts',
|
|
374
|
-
targetType: config.type,
|
|
375
|
-
config,
|
|
376
|
-
},
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
async function parseSeedMdxFile(filePath, relativePath, content) {
|
|
380
|
-
try {
|
|
381
|
-
const { data: frontmatter, content: mdxContent } = matter(content);
|
|
382
|
-
// Extract prompt from MDX content (strip frontmatter)
|
|
383
|
-
const prompt = mdxContent.trim() || undefined;
|
|
384
|
-
const config = {
|
|
385
|
-
...frontmatter,
|
|
386
|
-
prompt: (prompt || frontmatter.prompt),
|
|
387
|
-
};
|
|
388
|
-
return {
|
|
389
|
-
path: filePath,
|
|
390
|
-
relativePath,
|
|
391
|
-
format: 'mdx',
|
|
392
|
-
targetType: frontmatter.type,
|
|
393
|
-
config,
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
catch {
|
|
397
|
-
return null;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
// ============================================================================
|
|
401
|
-
// Workflow file parsing
|
|
402
|
-
// ============================================================================
|
|
403
|
-
function findWorkflowExport(ast) {
|
|
404
|
-
let config = null;
|
|
405
|
-
traverse(ast, {
|
|
406
|
-
ExportDefaultDeclaration(path) {
|
|
407
|
-
const declaration = path.node.declaration;
|
|
408
|
-
if (declaration && declaration.type === 'CallExpression') {
|
|
409
|
-
const callee = declaration.callee;
|
|
410
|
-
// Check for Workflow(...)
|
|
411
|
-
if (callee.type === 'Identifier' && callee.name === 'Workflow') {
|
|
412
|
-
if (declaration.arguments.length > 0) {
|
|
413
|
-
const arg = declaration.arguments[0];
|
|
414
|
-
if (arg.type === 'ObjectExpression') {
|
|
415
|
-
config = extractObjectValue(arg);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
},
|
|
421
|
-
});
|
|
422
|
-
return config;
|
|
423
|
-
}
|
|
424
|
-
async function parseWorkflowFile(filePath, relativePath, content) {
|
|
425
|
-
const parseResult = parseTypeScript(content);
|
|
426
|
-
if (!parseResult.ast) {
|
|
427
|
-
return { workflow: null, error: parseResult.error };
|
|
428
|
-
}
|
|
429
|
-
const config = findWorkflowExport(parseResult.ast);
|
|
430
|
-
if (!config)
|
|
431
|
-
return { workflow: null };
|
|
432
|
-
return {
|
|
433
|
-
workflow: {
|
|
434
|
-
path: filePath,
|
|
435
|
-
relativePath,
|
|
436
|
-
name: config.name,
|
|
437
|
-
trigger: config.trigger,
|
|
438
|
-
config,
|
|
439
|
-
},
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
// ============================================================================
|
|
443
|
-
// Config file loading
|
|
444
|
-
// ============================================================================
|
|
445
|
-
async function loadProjectConfig(root) {
|
|
446
|
-
// Try .ts first, then .js
|
|
447
|
-
const configFiles = ['db4.config.ts', 'db4.config.js'];
|
|
448
|
-
for (const configFile of configFiles) {
|
|
449
|
-
const configPath = join(root, configFile);
|
|
450
|
-
try {
|
|
451
|
-
await access(configPath);
|
|
452
|
-
const content = await readFile(configPath, 'utf-8');
|
|
453
|
-
// Parse the config file
|
|
454
|
-
if (configFile.endsWith('.ts')) {
|
|
455
|
-
return parseTsConfig(content);
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
return parseJsConfig(content);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
catch {
|
|
462
|
-
// File doesn't exist or can't be read
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
return undefined;
|
|
467
|
-
}
|
|
468
|
-
function parseTsConfig(content) {
|
|
469
|
-
const parseResult = parseTypeScript(content);
|
|
470
|
-
if (!parseResult.ast)
|
|
471
|
-
return undefined;
|
|
472
|
-
let config;
|
|
473
|
-
traverse(parseResult.ast, {
|
|
474
|
-
ExportDefaultDeclaration(path) {
|
|
475
|
-
const declaration = path.node.declaration;
|
|
476
|
-
if (declaration && declaration.type === 'ObjectExpression') {
|
|
477
|
-
config = extractObjectValue(declaration);
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
|
-
});
|
|
481
|
-
return config;
|
|
482
|
-
}
|
|
483
|
-
function parseJsConfig(content) {
|
|
484
|
-
// Handle CommonJS: module.exports = { ... }
|
|
485
|
-
const parseResult = parseTypeScript(content);
|
|
486
|
-
if (!parseResult.ast)
|
|
487
|
-
return undefined;
|
|
488
|
-
let config;
|
|
489
|
-
traverse(parseResult.ast, {
|
|
490
|
-
AssignmentExpression(path) {
|
|
491
|
-
const left = path.node.left;
|
|
492
|
-
const right = path.node.right;
|
|
493
|
-
// Check for module.exports = { ... }
|
|
494
|
-
if (left.type === 'MemberExpression' && left.object.type === 'Identifier' && left.object.name === 'module' && left.property.type === 'Identifier' && left.property.name === 'exports' && right.type === 'ObjectExpression') {
|
|
495
|
-
config = extractObjectValue(right);
|
|
496
|
-
}
|
|
497
|
-
},
|
|
498
|
-
});
|
|
499
|
-
return config;
|
|
500
|
-
}
|
|
501
|
-
// ============================================================================
|
|
502
|
-
// Main Scanner
|
|
503
|
-
// ============================================================================
|
|
504
|
-
export function createScanner(scannerConfig) {
|
|
505
|
-
const { root } = scannerConfig;
|
|
506
|
-
// Cache for incremental scanning
|
|
507
|
-
const cache = new Map();
|
|
508
|
-
async function scan(options = {}) {
|
|
509
|
-
const startTime = performance.now();
|
|
510
|
-
// Verify root directory exists
|
|
511
|
-
try {
|
|
512
|
-
const rootStat = await stat(root);
|
|
513
|
-
if (!rootStat.isDirectory()) {
|
|
514
|
-
throw new Error(`Not a directory: ${root}`);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
catch (err) {
|
|
518
|
-
throw new Error(`Cannot access directory: ${root}`);
|
|
519
|
-
}
|
|
520
|
-
const schemas = [];
|
|
521
|
-
const seeds = [];
|
|
522
|
-
const workflows = [];
|
|
523
|
-
const errors = [];
|
|
524
|
-
// Load project config first (it may override include/exclude patterns)
|
|
525
|
-
const projectConfig = await loadProjectConfig(root);
|
|
526
|
-
// Determine effective include/exclude patterns
|
|
527
|
-
const includePatterns = scannerConfig.include || projectConfig?.scan?.include;
|
|
528
|
-
const excludePatterns = scannerConfig.exclude || projectConfig?.scan?.exclude;
|
|
529
|
-
// Walk the directory
|
|
530
|
-
for await (const { path: filePath, relativePath } of walkDirectory(root, root)) {
|
|
531
|
-
// Check file extension
|
|
532
|
-
const ext = filePath.slice(filePath.lastIndexOf('.'));
|
|
533
|
-
if (ext !== '.ts' && ext !== '.mdx') {
|
|
534
|
-
continue;
|
|
535
|
-
}
|
|
536
|
-
// Apply include/exclude filters
|
|
537
|
-
if (!shouldIncludeFile(relativePath, includePatterns, excludePatterns)) {
|
|
538
|
-
continue;
|
|
539
|
-
}
|
|
540
|
-
try {
|
|
541
|
-
const content = await readFile(filePath, 'utf-8');
|
|
542
|
-
// Skip empty files
|
|
543
|
-
if (!content.trim()) {
|
|
544
|
-
continue;
|
|
545
|
-
}
|
|
546
|
-
// Determine file type and parse accordingly
|
|
547
|
-
if (relativePath.endsWith('.seed.ts')) {
|
|
548
|
-
const result = await parseSeedTsFile(filePath, relativePath, content);
|
|
549
|
-
if (result.error) {
|
|
550
|
-
errors.push({ path: filePath, error: result.error });
|
|
551
|
-
}
|
|
552
|
-
else if (result.seed) {
|
|
553
|
-
seeds.push(result.seed);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
else if (relativePath.endsWith('.seed.mdx')) {
|
|
557
|
-
const seedFile = await parseSeedMdxFile(filePath, relativePath, content);
|
|
558
|
-
if (seedFile) {
|
|
559
|
-
seeds.push(seedFile);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
else if (relativePath.endsWith('.workflow.ts')) {
|
|
563
|
-
const result = await parseWorkflowFile(filePath, relativePath, content);
|
|
564
|
-
if (result.error) {
|
|
565
|
-
errors.push({ path: filePath, error: result.error });
|
|
566
|
-
}
|
|
567
|
-
else if (result.workflow) {
|
|
568
|
-
workflows.push(result.workflow);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
else if (relativePath.endsWith('.schema.ts') || relativePath.endsWith('.db.ts')) {
|
|
572
|
-
// Schema files - allow bare DB() calls, reject non-mdxai imports
|
|
573
|
-
const result = await parseSchemaFile(filePath, relativePath, content, true);
|
|
574
|
-
if (result.error) {
|
|
575
|
-
errors.push({ path: filePath, error: result.error });
|
|
576
|
-
}
|
|
577
|
-
else if (result.schemas) {
|
|
578
|
-
schemas.push(...result.schemas);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
else if (ext === '.ts') {
|
|
582
|
-
// Regular .ts files - allow bare DB() calls, reject non-mdxai imports
|
|
583
|
-
const result = await parseSchemaFile(filePath, relativePath, content, true);
|
|
584
|
-
if (result.error) {
|
|
585
|
-
errors.push({ path: filePath, error: result.error });
|
|
586
|
-
}
|
|
587
|
-
else if (result.schemas) {
|
|
588
|
-
schemas.push(...result.schemas);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
catch (err) {
|
|
593
|
-
errors.push({
|
|
594
|
-
path: filePath,
|
|
595
|
-
error: err instanceof Error ? err.message : String(err),
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
const duration = performance.now() - startTime;
|
|
600
|
-
const result = {
|
|
601
|
-
root,
|
|
602
|
-
schemas,
|
|
603
|
-
seeds,
|
|
604
|
-
workflows,
|
|
605
|
-
duration,
|
|
606
|
-
};
|
|
607
|
-
if (projectConfig) {
|
|
608
|
-
result.config = projectConfig;
|
|
609
|
-
}
|
|
610
|
-
if (errors.length > 0) {
|
|
611
|
-
result.errors = errors;
|
|
612
|
-
}
|
|
613
|
-
return result;
|
|
614
|
-
}
|
|
615
|
-
function watch(callback) {
|
|
616
|
-
// For now, just return a no-op unsubscribe function
|
|
617
|
-
// A full implementation would use fs.watch or chokidar
|
|
618
|
-
let isWatching = true;
|
|
619
|
-
// Do an initial scan (catch errors to avoid unhandled rejections)
|
|
620
|
-
scan()
|
|
621
|
-
.then((result) => {
|
|
622
|
-
if (isWatching) {
|
|
623
|
-
callback(result);
|
|
624
|
-
}
|
|
625
|
-
})
|
|
626
|
-
.catch(() => {
|
|
627
|
-
// Ignore errors if we've already unsubscribed
|
|
628
|
-
});
|
|
629
|
-
return () => {
|
|
630
|
-
isWatching = false;
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
return {
|
|
634
|
-
scan,
|
|
635
|
-
watch,
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
// Re-export minimatch for tests that might need it
|
|
639
|
-
export { minimatch };
|
|
1
|
+
import {
|
|
2
|
+
createScanner,
|
|
3
|
+
minimatch
|
|
4
|
+
} from "../../chunk-Y5IXAS7F.js";
|
|
5
|
+
export {
|
|
6
|
+
createScanner,
|
|
7
|
+
minimatch
|
|
8
|
+
};
|
|
640
9
|
//# sourceMappingURL=index.js.map
|