on-zero 0.16.17 → 0.16.19
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/cjs/createZeroClient.cjs +44 -11
- package/dist/cjs/createZeroClient.native.js +54 -17
- package/dist/cjs/createZeroClient.native.js.map +1 -1
- package/dist/cjs/createZeroClient.recovery.test.cjs +49 -0
- package/dist/cjs/createZeroClient.recovery.test.native.js +53 -0
- package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/cjs/generate-helpers.cjs +28 -0
- package/dist/cjs/generate-helpers.native.js +36 -0
- package/dist/cjs/generate-helpers.native.js.map +1 -1
- package/dist/cjs/generate-layout.cjs +62 -53
- package/dist/cjs/generate-layout.native.js +62 -54
- package/dist/cjs/generate-layout.native.js.map +1 -1
- package/dist/cjs/generate-lite.cjs +28 -0
- package/dist/cjs/generate-lite.native.js +89 -33
- package/dist/cjs/generate-lite.native.js.map +1 -1
- package/dist/cjs/generate-lite.test.cjs +46 -0
- package/dist/cjs/generate-lite.test.native.js +46 -0
- package/dist/cjs/generate-lite.test.native.js.map +1 -1
- package/dist/cjs/generate.cjs +237 -243
- package/dist/cjs/generate.native.js +352 -353
- package/dist/cjs/generate.native.js.map +1 -1
- package/dist/cjs/generate.test.cjs +35 -0
- package/dist/cjs/generate.test.native.js +35 -0
- package/dist/cjs/generate.test.native.js.map +1 -1
- package/dist/cjs/helpers/createMutators.cjs +2 -1
- package/dist/cjs/helpers/createMutators.native.js +3 -1
- package/dist/cjs/helpers/createMutators.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.cjs +8 -2
- package/dist/cjs/helpers/recoverZeroClient.native.js +10 -2
- package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.test.cjs +53 -0
- package/dist/cjs/helpers/recoverZeroClient.test.native.js +55 -0
- package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/cjs/native-typescript.cjs +190 -0
- package/dist/cjs/native-typescript.native.js +255 -0
- package/dist/cjs/native-typescript.native.js.map +1 -0
- package/dist/esm/createZeroClient.mjs +44 -11
- package/dist/esm/createZeroClient.mjs.map +1 -1
- package/dist/esm/createZeroClient.native.js +54 -17
- package/dist/esm/createZeroClient.native.js.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.mjs +50 -1
- package/dist/esm/createZeroClient.recovery.test.mjs.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.native.js +54 -1
- package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/esm/generate-helpers.mjs +27 -1
- package/dist/esm/generate-helpers.mjs.map +1 -1
- package/dist/esm/generate-helpers.native.js +35 -1
- package/dist/esm/generate-helpers.native.js.map +1 -1
- package/dist/esm/generate-layout.mjs +52 -54
- package/dist/esm/generate-layout.mjs.map +1 -1
- package/dist/esm/generate-layout.native.js +52 -55
- package/dist/esm/generate-layout.native.js.map +1 -1
- package/dist/esm/generate-lite.mjs +29 -1
- package/dist/esm/generate-lite.mjs.map +1 -1
- package/dist/esm/generate-lite.native.js +90 -34
- package/dist/esm/generate-lite.native.js.map +1 -1
- package/dist/esm/generate-lite.test.mjs +46 -0
- package/dist/esm/generate-lite.test.mjs.map +1 -1
- package/dist/esm/generate-lite.test.native.js +46 -0
- package/dist/esm/generate-lite.test.native.js.map +1 -1
- package/dist/esm/generate.mjs +238 -244
- package/dist/esm/generate.mjs.map +1 -1
- package/dist/esm/generate.native.js +353 -354
- package/dist/esm/generate.native.js.map +1 -1
- package/dist/esm/generate.test.mjs +35 -0
- package/dist/esm/generate.test.mjs.map +1 -1
- package/dist/esm/generate.test.native.js +35 -0
- package/dist/esm/generate.test.native.js.map +1 -1
- package/dist/esm/helpers/createMutators.mjs +2 -1
- package/dist/esm/helpers/createMutators.mjs.map +1 -1
- package/dist/esm/helpers/createMutators.native.js +3 -1
- package/dist/esm/helpers/createMutators.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.mjs +8 -2
- package/dist/esm/helpers/recoverZeroClient.mjs.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.native.js +10 -2
- package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.mjs +53 -0
- package/dist/esm/helpers/recoverZeroClient.test.mjs.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.native.js +55 -0
- package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/native-typescript.mjs +164 -0
- package/dist/esm/native-typescript.mjs.map +1 -0
- package/dist/esm/native-typescript.native.js +226 -0
- package/dist/esm/native-typescript.native.js.map +1 -0
- package/package.json +4 -3
- package/src/createZeroClient.recovery.test.tsx +56 -1
- package/src/createZeroClient.tsx +54 -15
- package/src/generate-helpers.ts +79 -0
- package/src/generate-layout.ts +64 -108
- package/src/generate-lite.test.ts +49 -0
- package/src/generate-lite.ts +44 -0
- package/src/generate.test.ts +52 -0
- package/src/generate.ts +313 -366
- package/src/helpers/createMutators.ts +14 -3
- package/src/helpers/recoverZeroClient.test.ts +50 -0
- package/src/helpers/recoverZeroClient.ts +12 -2
- package/src/native-typescript.ts +176 -0
- package/types/createZeroClient.d.ts.map +1 -1
- package/types/generate-helpers.d.ts +13 -0
- package/types/generate-helpers.d.ts.map +1 -1
- package/types/generate-layout.d.ts +2 -1
- package/types/generate-layout.d.ts.map +1 -1
- package/types/generate-lite.d.ts +1 -0
- package/types/generate-lite.d.ts.map +1 -1
- package/types/generate.d.ts.map +1 -1
- package/types/helpers/createMutators.d.ts.map +1 -1
- package/types/helpers/recoverZeroClient.d.ts.map +1 -1
- package/types/native-typescript.d.ts +11 -0
- package/types/native-typescript.d.ts.map +1 -0
package/dist/esm/generate.mjs
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { basename, dirname, resolve } from "node:path";
|
|
4
|
-
import
|
|
4
|
+
import * as ts from "typescript/unstable/ast";
|
|
5
|
+
import { ObjectFlags, SymbolFlags, TypeFlags } from "typescript/unstable/async";
|
|
6
|
+
import { CRUD_MUTATION_NAMES, formatObjectKey, generateAggregatesFile, generateGroupedQueriesFile, generateInstancesFile, generateModelsFile, generateReadmeFile, generateSyncedMutationsFile, generateSyncedQueriesFile, generateTablesFile, generateTypesFile, parseColumnType, parseTypeString, renderDrizzleZeroSqliteSchemaModule, shouldSkipObjectKey } from "./generate-helpers.mjs";
|
|
5
7
|
import { discoverDataLayout, namespaceImportPath } from "./generate-layout.mjs";
|
|
8
|
+
import { collectTypeScriptSourcePaths, createNativeTypeScriptProject } from "./native-typescript.mjs";
|
|
6
9
|
const hash = s => createHash("sha256").update(s).digest("hex");
|
|
7
|
-
const GENERATOR_CACHE_VERSION = "
|
|
10
|
+
const GENERATOR_CACHE_VERSION = "7";
|
|
8
11
|
const isGeneratorSourceFile = name => name.endsWith(".ts") && !name.endsWith(".d.ts") && !name.endsWith(".test.ts") && !name.endsWith(".spec.ts");
|
|
9
12
|
function hashInputTree(sourceRoots, generatedDir) {
|
|
10
13
|
const parts = [];
|
|
@@ -65,72 +68,37 @@ function saveCache() {
|
|
|
65
68
|
}
|
|
66
69
|
function writeFileIfChanged(filePath, content) {
|
|
67
70
|
const contentHash = hash(content);
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
let onDisk = null;
|
|
72
|
+
try {
|
|
73
|
+
onDisk = readFileSync(filePath, "utf-8");
|
|
74
|
+
} catch {}
|
|
75
|
+
if (onDisk !== null && hash(onDisk) === contentHash) {
|
|
76
|
+
generateCache[filePath] = contentHash;
|
|
70
77
|
return false;
|
|
71
78
|
}
|
|
72
79
|
writeFileSync(filePath, content, "utf-8");
|
|
73
80
|
generateCache[filePath] = contentHash;
|
|
74
81
|
return true;
|
|
75
82
|
}
|
|
76
|
-
function createTypeResolver(
|
|
77
|
-
const configPath = ts.findConfigFile(dir, ts.sys.fileExists, "tsconfig.json");
|
|
78
|
-
let compilerOptions = {
|
|
79
|
-
target: ts.ScriptTarget.Latest,
|
|
80
|
-
module: ts.ModuleKind.ESNext,
|
|
81
|
-
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
82
|
-
strict: false,
|
|
83
|
-
skipLibCheck: true,
|
|
84
|
-
noEmit: true
|
|
85
|
-
};
|
|
86
|
-
if (configPath) {
|
|
87
|
-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
88
|
-
if (configFile.config) {
|
|
89
|
-
const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(configPath));
|
|
90
|
-
compilerOptions = {
|
|
91
|
-
...compilerOptions,
|
|
92
|
-
...parsed.options
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const fileMap = /* @__PURE__ */new Map();
|
|
97
|
-
for (const f of files) {
|
|
98
|
-
fileMap.set(f.path, f.content);
|
|
99
|
-
}
|
|
100
|
-
const host = ts.createCompilerHost(compilerOptions);
|
|
101
|
-
const originalGetSourceFile = host.getSourceFile.bind(host);
|
|
102
|
-
host.getSourceFile = (fileName, languageVersion, onError) => {
|
|
103
|
-
const content = fileMap.get(fileName);
|
|
104
|
-
if (content !== void 0) {
|
|
105
|
-
return ts.createSourceFile(fileName, content, languageVersion, true);
|
|
106
|
-
}
|
|
107
|
-
return originalGetSourceFile(fileName, languageVersion, onError);
|
|
108
|
-
};
|
|
109
|
-
host.fileExists = fileName => fileMap.has(fileName) || ts.sys.fileExists(fileName);
|
|
110
|
-
host.readFile = fileName => fileMap.get(fileName) ?? ts.sys.readFile(fileName);
|
|
111
|
-
const program = ts.createProgram(files.map(f => f.path), compilerOptions, host);
|
|
112
|
-
const checker = program.getTypeChecker();
|
|
83
|
+
function createTypeResolver(project) {
|
|
113
84
|
return {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// resolve a type annotation node to a ts.Type
|
|
117
|
-
resolveType(node) {
|
|
85
|
+
project,
|
|
86
|
+
async resolveType(node) {
|
|
118
87
|
try {
|
|
119
|
-
return checker.getTypeFromTypeNode(node);
|
|
88
|
+
return (await project.checker.getTypeFromTypeNode(node)) ?? null;
|
|
120
89
|
} catch {
|
|
121
90
|
return null;
|
|
122
91
|
}
|
|
123
92
|
},
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return tsTypeToValibot(ts, checker, type);
|
|
93
|
+
async typeToValibot(type) {
|
|
94
|
+
return tsTypeToValibot(project, type);
|
|
127
95
|
}
|
|
128
96
|
};
|
|
129
97
|
}
|
|
130
|
-
function resolveParamType(
|
|
131
|
-
let
|
|
132
|
-
|
|
133
|
-
if (
|
|
98
|
+
async function resolveParamType(resolver, sourceFile, exportName, paramIndex) {
|
|
99
|
+
let typeNode = null;
|
|
100
|
+
sourceFile.forEachChild(node => {
|
|
101
|
+
if (typeNode) return;
|
|
134
102
|
if (!ts.isVariableStatement(node)) return;
|
|
135
103
|
if (!node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) return;
|
|
136
104
|
const decl = node.declarationList.declarations[0];
|
|
@@ -139,13 +107,13 @@ function resolveParamType(ts, resolver, sourceFile, exportName, paramIndex) {
|
|
|
139
107
|
if (decl.initializer && ts.isArrowFunction(decl.initializer)) {
|
|
140
108
|
const param = decl.initializer.parameters[paramIndex];
|
|
141
109
|
if (param?.type) {
|
|
142
|
-
|
|
110
|
+
typeNode = param.type;
|
|
143
111
|
}
|
|
144
112
|
}
|
|
145
113
|
});
|
|
146
|
-
return
|
|
114
|
+
return typeNode ? resolver.resolveType(typeNode) : null;
|
|
147
115
|
}
|
|
148
|
-
function readMutationsCall(
|
|
116
|
+
function readMutationsCall(call) {
|
|
149
117
|
const args = call.arguments;
|
|
150
118
|
if (args.length < 2) {
|
|
151
119
|
const only = args[0];
|
|
@@ -171,9 +139,9 @@ function readMutationsCall(ts, call) {
|
|
|
171
139
|
handlersArg: handlers && ts.isObjectLiteralExpression(handlers) ? handlers : null
|
|
172
140
|
};
|
|
173
141
|
}
|
|
174
|
-
function resolveMutationParamTypes(
|
|
175
|
-
const
|
|
176
|
-
|
|
142
|
+
async function resolveMutationParamTypes(resolver, sourceFile) {
|
|
143
|
+
const nodes = /* @__PURE__ */new Map();
|
|
144
|
+
sourceFile.forEachChild(node => {
|
|
177
145
|
if (!ts.isVariableStatement(node)) return;
|
|
178
146
|
if (!node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) return;
|
|
179
147
|
const decl = node.declarationList.declarations[0];
|
|
@@ -182,7 +150,7 @@ function resolveMutationParamTypes(ts, resolver, sourceFile) {
|
|
|
182
150
|
if (!decl.initializer || !ts.isCallExpression(decl.initializer)) return;
|
|
183
151
|
const {
|
|
184
152
|
handlersArg
|
|
185
|
-
} = readMutationsCall(
|
|
153
|
+
} = readMutationsCall(decl.initializer);
|
|
186
154
|
if (!handlersArg) return;
|
|
187
155
|
for (const prop of handlersArg.properties) {
|
|
188
156
|
if (!ts.isPropertyAssignment(prop) && !ts.isMethodDeclaration(prop)) continue;
|
|
@@ -200,17 +168,19 @@ function resolveMutationParamTypes(ts, resolver, sourceFile) {
|
|
|
200
168
|
if (!params || params.length < 2) continue;
|
|
201
169
|
const typeNode = params[1].type;
|
|
202
170
|
if (!typeNode) continue;
|
|
203
|
-
|
|
204
|
-
if (expanded) {
|
|
205
|
-
resolved.set(name, expanded);
|
|
206
|
-
}
|
|
171
|
+
nodes.set(name, typeNode);
|
|
207
172
|
}
|
|
208
173
|
});
|
|
174
|
+
const resolved = /* @__PURE__ */new Map();
|
|
175
|
+
for (const [name, node] of nodes) {
|
|
176
|
+
const expanded = await resolver.resolveType(node);
|
|
177
|
+
if (expanded) resolved.set(name, expanded);
|
|
178
|
+
}
|
|
209
179
|
return resolved;
|
|
210
180
|
}
|
|
211
|
-
function extractMutationsFromModel(
|
|
181
|
+
function extractMutationsFromModel(sourceFile, content, fileName, silent, typeToValibot, resolvedValibot) {
|
|
212
182
|
let mutateNode = null;
|
|
213
|
-
|
|
183
|
+
sourceFile.forEachChild(node => {
|
|
214
184
|
if (!ts.isVariableStatement(node)) return;
|
|
215
185
|
if (!node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) return;
|
|
216
186
|
const decl = node.declarationList.declarations[0];
|
|
@@ -234,12 +204,12 @@ function extractMutationsFromModel(ts, sourceFile, content, fileName, silent, ty
|
|
|
234
204
|
hasTable,
|
|
235
205
|
crud,
|
|
236
206
|
handlersArg
|
|
237
|
-
} = readMutationsCall(
|
|
207
|
+
} = readMutationsCall(call);
|
|
238
208
|
const hasCRUD = hasTable && crud;
|
|
239
209
|
const columns = {};
|
|
240
210
|
const primaryKeys = [];
|
|
241
211
|
if (hasCRUD) {
|
|
242
|
-
extractSchemaColumns(
|
|
212
|
+
extractSchemaColumns(sourceFile, columns, primaryKeys);
|
|
243
213
|
}
|
|
244
214
|
const custom = [];
|
|
245
215
|
if (handlersArg) {
|
|
@@ -276,11 +246,8 @@ function extractMutationsFromModel(ts, sourceFile, content, fileName, silent, ty
|
|
|
276
246
|
continue;
|
|
277
247
|
}
|
|
278
248
|
let valibotCode = typeToValibot(paramType);
|
|
279
|
-
if (!valibotCode &&
|
|
280
|
-
|
|
281
|
-
if (resolvedType) {
|
|
282
|
-
valibotCode = resolvedTypeToValibot(resolvedType);
|
|
283
|
-
}
|
|
249
|
+
if (!valibotCode && resolvedValibot) {
|
|
250
|
+
valibotCode = resolvedValibot.get(name) ?? null;
|
|
284
251
|
}
|
|
285
252
|
custom.push({
|
|
286
253
|
name,
|
|
@@ -297,7 +264,7 @@ function extractMutationsFromModel(ts, sourceFile, content, fileName, silent, ty
|
|
|
297
264
|
custom
|
|
298
265
|
};
|
|
299
266
|
}
|
|
300
|
-
function extractSchemaColumns(
|
|
267
|
+
function extractSchemaColumns(sourceFile, columns, primaryKeys) {
|
|
301
268
|
function visit(node) {
|
|
302
269
|
if (ts.isCallExpression(node)) {
|
|
303
270
|
const text = node.expression.getText(sourceFile);
|
|
@@ -322,80 +289,75 @@ function extractSchemaColumns(ts, sourceFile, columns, primaryKeys) {
|
|
|
322
289
|
}
|
|
323
290
|
}
|
|
324
291
|
}
|
|
325
|
-
|
|
292
|
+
node.forEachChild(visit);
|
|
326
293
|
}
|
|
327
294
|
visit(sourceFile);
|
|
328
295
|
}
|
|
329
|
-
function
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
if (flags &
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (flags &
|
|
343
|
-
if (flags &
|
|
344
|
-
if (flags &
|
|
345
|
-
if (flags &
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const elementType = typeArgs.length === 1 ? typeArgs[0] : type.getNumberIndexType?.();
|
|
353
|
-
return `v.array(${elementType ? recurse(elementType) : "v.unknown()"})`;
|
|
354
|
-
}
|
|
355
|
-
if (flags & ts.TypeFlags.StringLiteral) {
|
|
296
|
+
async function tsTypeToValibot(project, type, seen = /* @__PURE__ */new Set()) {
|
|
297
|
+
const checker = project.checker;
|
|
298
|
+
const flags = type.flags;
|
|
299
|
+
if (flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
|
300
|
+
if (seen.has(type.id)) return "v.unknown()";
|
|
301
|
+
seen.add(type.id);
|
|
302
|
+
}
|
|
303
|
+
const recurse = value => tsTypeToValibot(project, value, seen);
|
|
304
|
+
if (flags & TypeFlags.String) return "v.string()";
|
|
305
|
+
if (flags & TypeFlags.Number) return "v.number()";
|
|
306
|
+
if (flags & TypeFlags.Boolean) return "v.boolean()";
|
|
307
|
+
if (flags & TypeFlags.Void || flags & TypeFlags.Undefined) return "v.void_()";
|
|
308
|
+
if (flags & TypeFlags.Null) return "v.null_()";
|
|
309
|
+
if (flags & TypeFlags.Any || flags & TypeFlags.Unknown) return "v.unknown()";
|
|
310
|
+
if (flags & TypeFlags.Never) return "v.never()";
|
|
311
|
+
if (flags & TypeFlags.TemplateLiteral) return "v.string()";
|
|
312
|
+
if (flags & TypeFlags.Object && (await checker.isArrayLikeType(type))) {
|
|
313
|
+
const typeArgs = type.isTypeReference() ? await checker.getTypeArguments(type) : [];
|
|
314
|
+
const indexInfo = (await checker.getIndexInfosOfType(type)).find(info => Boolean(info.keyType.flags & TypeFlags.Number));
|
|
315
|
+
const elementType = typeArgs.length === 1 ? typeArgs[0] : indexInfo?.valueType;
|
|
316
|
+
return `v.array(${elementType ? await recurse(elementType) : "v.unknown()"})`;
|
|
317
|
+
}
|
|
318
|
+
if (type.isStringLiteralType()) {
|
|
356
319
|
return `v.literal(${JSON.stringify(type.value)})`;
|
|
357
320
|
}
|
|
358
|
-
if (
|
|
321
|
+
if (type.isNumberLiteralType()) {
|
|
359
322
|
return `v.literal(${type.value})`;
|
|
360
323
|
}
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
return `v.literal(${name === "true"})`;
|
|
324
|
+
if (type.isBooleanLiteralType()) {
|
|
325
|
+
return `v.literal(${type.value})`;
|
|
364
326
|
}
|
|
365
|
-
if (type.
|
|
366
|
-
const members = type.
|
|
367
|
-
const hasNull = members.some(
|
|
368
|
-
const hasUndefined = members.some(
|
|
369
|
-
const rest = members.filter(
|
|
370
|
-
if (rest.length === 2 && rest.every(
|
|
327
|
+
if (type.isUnionType()) {
|
|
328
|
+
const members = await type.getTypes();
|
|
329
|
+
const hasNull = members.some(member => member.flags & TypeFlags.Null);
|
|
330
|
+
const hasUndefined = members.some(member => member.flags & (TypeFlags.Undefined | TypeFlags.Void));
|
|
331
|
+
const rest = members.filter(member => !(member.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.Void)));
|
|
332
|
+
if (rest.length === 2 && rest.every(member => member.flags & TypeFlags.BooleanLiteral)) {
|
|
371
333
|
let inner2 = "v.boolean()";
|
|
372
334
|
if (hasNull) inner2 = `v.nullable(${inner2})`;
|
|
373
335
|
if (hasUndefined) inner2 = `v.optional(${inner2})`;
|
|
374
336
|
return inner2;
|
|
375
337
|
}
|
|
376
338
|
if (rest.length === 0) return "v.unknown()";
|
|
377
|
-
let inner = rest.length === 1 ? recurse(rest[0]) : `v.union([${rest.map(
|
|
339
|
+
let inner = rest.length === 1 ? await recurse(rest[0]) : `v.union([${(await Promise.all(rest.map(recurse))).join(", ")}])`;
|
|
378
340
|
if (hasNull) inner = `v.nullable(${inner})`;
|
|
379
341
|
if (hasUndefined) inner = `v.optional(${inner})`;
|
|
380
342
|
return inner;
|
|
381
343
|
}
|
|
382
|
-
const resolveSymbolType =
|
|
383
|
-
const
|
|
384
|
-
if (
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return checker.
|
|
344
|
+
const resolveSymbolType = async property => {
|
|
345
|
+
const symbolType = await checker.getTypeOfSymbol(property);
|
|
346
|
+
if (symbolType && !symbolType.isErrorType()) return symbolType;
|
|
347
|
+
const declaration = property.valueDeclaration ?? property.declarations[0];
|
|
348
|
+
const node = declaration ? await declaration.resolve(project) : void 0;
|
|
349
|
+
if (node) return checker.getTypeOfSymbolAtLocation(property, node);
|
|
350
|
+
return checker.getDeclaredTypeOfSymbol(property);
|
|
388
351
|
};
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if (props2.length === 0) return "v.object({})";
|
|
352
|
+
const objectToValibot = async props => {
|
|
353
|
+
if (props.length === 0) return "v.object({})";
|
|
392
354
|
const entries = [];
|
|
393
|
-
for (const prop of
|
|
394
|
-
const name = prop.
|
|
355
|
+
for (const prop of props) {
|
|
356
|
+
const name = prop.name;
|
|
395
357
|
if (shouldSkipObjectKey(name)) continue;
|
|
396
|
-
const propType = resolveSymbolType(
|
|
397
|
-
const isOptional =
|
|
398
|
-
let val = recurse(propType);
|
|
358
|
+
const propType = await resolveSymbolType(prop);
|
|
359
|
+
const isOptional = Boolean(prop.flags & SymbolFlags.Optional);
|
|
360
|
+
let val = await recurse(propType);
|
|
399
361
|
if (isOptional && !val.startsWith("v.optional(")) {
|
|
400
362
|
val = `v.optional(${val})`;
|
|
401
363
|
}
|
|
@@ -405,47 +367,32 @@ function tsTypeToValibot(ts, checker, type, seen) {
|
|
|
405
367
|
return `v.object({
|
|
406
368
|
${entries.join(",\n ")},
|
|
407
369
|
})`;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
370
|
+
};
|
|
371
|
+
if (type.isIntersectionType()) {
|
|
372
|
+
return objectToValibot(await checker.getPropertiesOfType(type));
|
|
373
|
+
}
|
|
374
|
+
if (type.isTupleType()) {
|
|
375
|
+
const typeArgs = await checker.getTypeArguments(type);
|
|
376
|
+
return `v.tuple([${(await Promise.all(typeArgs.map(recurse))).join(", ")}])`;
|
|
377
|
+
}
|
|
378
|
+
if (type.isObjectType()) {
|
|
379
|
+
if (type.objectFlags & ObjectFlags.Reference && type.isTypeReference()) {
|
|
380
|
+
const symbol = await type.getSymbol();
|
|
381
|
+
const typeArgs = await checker.getTypeArguments(type);
|
|
382
|
+
if ((symbol?.name === "Array" || symbol?.name === "ReadonlyArray") && typeArgs.length === 1) {
|
|
383
|
+
return `v.array(${await recurse(typeArgs[0])})`;
|
|
418
384
|
}
|
|
419
385
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
386
|
+
const props = await checker.getPropertiesOfType(type);
|
|
387
|
+
if (props.length > 0) return objectToValibot(props);
|
|
388
|
+
}
|
|
389
|
+
for (const indexInfo of await checker.getIndexInfosOfType(type)) {
|
|
390
|
+
if (indexInfo.keyType.flags & TypeFlags.String) {
|
|
391
|
+
return `v.record(v.string(), ${await recurse(indexInfo.valueType)})`;
|
|
424
392
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const name = prop.getName();
|
|
428
|
-
if (shouldSkipObjectKey(name)) continue;
|
|
429
|
-
const propType = resolveSymbolType(type, prop);
|
|
430
|
-
const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional);
|
|
431
|
-
let val = recurse(propType);
|
|
432
|
-
if (isOptional && !val.startsWith("v.optional(")) {
|
|
433
|
-
val = `v.optional(${val})`;
|
|
434
|
-
}
|
|
435
|
-
entries.push(`${formatObjectKey(name)}: ${val}`);
|
|
393
|
+
if (indexInfo.keyType.flags & TypeFlags.Number) {
|
|
394
|
+
return `v.record(v.number(), ${await recurse(indexInfo.valueType)})`;
|
|
436
395
|
}
|
|
437
|
-
if (entries.length === 0) return "v.object({})";
|
|
438
|
-
return `v.object({
|
|
439
|
-
${entries.join(",\n ")},
|
|
440
|
-
})`;
|
|
441
|
-
}
|
|
442
|
-
const stringIndex = type.getStringIndexType();
|
|
443
|
-
if (stringIndex) {
|
|
444
|
-
return `v.record(v.string(), ${recurse(stringIndex)})`;
|
|
445
|
-
}
|
|
446
|
-
const numberIndex = type.getNumberIndexType();
|
|
447
|
-
if (numberIndex) {
|
|
448
|
-
return `v.record(v.number(), ${recurse(numberIndex)})`;
|
|
449
396
|
}
|
|
450
397
|
return "v.unknown()";
|
|
451
398
|
}
|
|
@@ -536,24 +483,41 @@ function dataMembershipFromLayout(layout) {
|
|
|
536
483
|
allTables: [...new Set(layout.instances.flatMap(instance => [...instance.syncTables, ...instance.supportTables]))].sort()
|
|
537
484
|
};
|
|
538
485
|
}
|
|
486
|
+
async function loadGeneratorProject(baseDir) {
|
|
487
|
+
const sourcePaths = collectTypeScriptSourcePaths([baseDir, resolve(dirname(baseDir), "database")]);
|
|
488
|
+
return createNativeTypeScriptProject(baseDir, sourcePaths);
|
|
489
|
+
}
|
|
539
490
|
async function deriveDataMembership(options) {
|
|
540
|
-
const
|
|
541
|
-
const
|
|
542
|
-
|
|
491
|
+
const baseDir = resolve(options.dir);
|
|
492
|
+
const project = await loadGeneratorProject(baseDir);
|
|
493
|
+
try {
|
|
494
|
+
const layout = discoverDataLayout(project, baseDir, options.config ? resolve(options.config) : void 0);
|
|
495
|
+
return dataMembershipFromLayout(layout);
|
|
496
|
+
} finally {
|
|
497
|
+
await project.close();
|
|
498
|
+
}
|
|
543
499
|
}
|
|
544
500
|
async function generateDrizzleSchemaInputFile(options) {
|
|
545
|
-
const ts = await import("typescript");
|
|
546
501
|
const baseDir = resolve(options.dir);
|
|
547
|
-
const
|
|
502
|
+
const project = await loadGeneratorProject(baseDir);
|
|
503
|
+
try {
|
|
504
|
+
return generateDrizzleSchemaInputFileWithProject(options, project);
|
|
505
|
+
} finally {
|
|
506
|
+
await project.close();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async function generateDrizzleSchemaInputFileWithProject(options, project) {
|
|
510
|
+
const baseDir = resolve(options.dir);
|
|
511
|
+
const layout = discoverDataLayout(project, baseDir, options.config ? resolve(options.config) : void 0);
|
|
548
512
|
const tableNames = dataMembershipFromLayout(layout).allTables;
|
|
549
513
|
const relationsPath = layout.metadataPaths.find(path => basename(path) === "relations.ts" && dirname(path) === resolve(dirname(baseDir), "database")) ?? layout.metadataPaths.find(path => basename(path) === "relations.ts");
|
|
550
514
|
const relationEntries = [];
|
|
551
515
|
if (relationsPath) {
|
|
552
|
-
const source =
|
|
516
|
+
const source = project.sourceFile(relationsPath);
|
|
553
517
|
const included = new Set(tableNames);
|
|
554
518
|
const visit = node => {
|
|
555
519
|
if (!ts.isCallExpression(node) || node.expression.getText(source) !== "defineRelations") {
|
|
556
|
-
|
|
520
|
+
node.forEachChild(visit);
|
|
557
521
|
return;
|
|
558
522
|
}
|
|
559
523
|
const factory = node.arguments[1];
|
|
@@ -587,6 +551,14 @@ ${relations.map(relation => ` ${relation},`).join("\n")}
|
|
|
587
551
|
return ["// auto-generated from the on-zero data layout", `import { defineRelations } from 'drizzle-orm'`, `import * as schema from ${schemaImportPath}`, "", `export { ${tableNames.join(", ")} } from ${schemaImportPath}`, `export const relations = defineRelations(schema, (r) => ({`, ...relationEntries, `}))`, ""].join("\n");
|
|
588
552
|
}
|
|
589
553
|
async function generate(options) {
|
|
554
|
+
const project = await loadGeneratorProject(resolve(options.dir));
|
|
555
|
+
try {
|
|
556
|
+
return await generateWithProject(options, project);
|
|
557
|
+
} finally {
|
|
558
|
+
await project.close();
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
async function generateWithProject(options, project) {
|
|
590
562
|
const {
|
|
591
563
|
dir,
|
|
592
564
|
after,
|
|
@@ -602,11 +574,41 @@ async function generate(options) {
|
|
|
602
574
|
});
|
|
603
575
|
}
|
|
604
576
|
loadCache();
|
|
605
|
-
const
|
|
606
|
-
const layout = discoverDataLayout(ts, baseDir, config ? resolve(config) : void 0);
|
|
577
|
+
const layout = discoverDataLayout(project, baseDir, config ? resolve(config) : void 0);
|
|
607
578
|
const metadataHash = hash(layout.metadataPaths.map(path => `${path}\0${readFileSync(path, "utf8")}`).join("\0"));
|
|
579
|
+
const databaseSchemaPath = resolve(dirname(baseDir), "database/schema.ts");
|
|
580
|
+
const needsSqliteZeroSchema = existsSync(databaseSchemaPath);
|
|
608
581
|
const inputHash = hash(`${hashInputTree(layout.sourceRoots, generatedDir)}\0${metadataHash}`);
|
|
609
|
-
if (!force && generateCache.__generatorVersion === GENERATOR_CACHE_VERSION && generateCache.__inputHash === inputHash &&
|
|
582
|
+
if (!force && generateCache.__generatorVersion === GENERATOR_CACHE_VERSION && generateCache.__inputHash === inputHash &&
|
|
583
|
+
// the input hash deliberately skips the generated directory, so it cannot
|
|
584
|
+
// notice that the outputs themselves moved. existence is not correctness
|
|
585
|
+
// either: a checkout, merge or revert leaves every file present and stale.
|
|
586
|
+
// confirm the bytes on disk still match what the cache says it wrote there
|
|
587
|
+
// before skipping the build, or the fast path serves someone else's output.
|
|
588
|
+
//
|
|
589
|
+
// a consumer that formats generated output after this runs never hits the
|
|
590
|
+
// fast path again, because the cache holds the bytes written here and disk
|
|
591
|
+
// holds the formatted ones. soot does exactly that, `on-zero generate &&
|
|
592
|
+
// generate-instance-tables && oxfmt src/data/generated/`, and the number is
|
|
593
|
+
// already taken: 2.50s median before, 3.69s after, four warm runs each in
|
|
594
|
+
// one checkout with only the pin swapped, so about 1.2 seconds or 47
|
|
595
|
+
// percent on this step. the full three-command script went 2.65s to 3.14s
|
|
596
|
+
// with a spread that swallows most of it.
|
|
597
|
+
//
|
|
598
|
+
// the shape matters more than the number. this is not a cache that hits
|
|
599
|
+
// less often, it is a cache that never hits, so the cost does not degrade
|
|
600
|
+
// gracefully and grows with the generated output rather than staying at
|
|
601
|
+
// 1.2s. correct and slower beats fast and stale, which is why it is written
|
|
602
|
+
// this way, but if generate time ever becomes the complaint, record the
|
|
603
|
+
// hash after the consumer's formatter runs rather than weakening this.
|
|
604
|
+
Object.entries(generateCache).every(([cachedPath, cachedHash]) => {
|
|
605
|
+
if (!cachedPath.startsWith(generatedDir)) return true;
|
|
606
|
+
try {
|
|
607
|
+
return hash(readFileSync(cachedPath, "utf-8")) === cachedHash;
|
|
608
|
+
} catch {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
}) && existsSync(resolve(generatedDir, "models.ts")) && (!needsSqliteZeroSchema || existsSync(resolve(generatedDir, "schema.ts")))) {
|
|
610
612
|
let counts = {};
|
|
611
613
|
try {
|
|
612
614
|
counts = JSON.parse(generateCache.__counts || "{}");
|
|
@@ -635,6 +637,24 @@ async function generate(options) {
|
|
|
635
637
|
// managed externally and should not be overwritten.
|
|
636
638
|
...(filesWithSchema.length > 0 ? [writeFileIfChanged(resolve(generatedDir, "types.ts"), generateTypesFile(schemaModules.map(module => module.name))), writeFileIfChanged(resolve(generatedDir, "tables.ts"), generateTablesFile(schemaModules))] : []), writeFileIfChanged(resolve(generatedDir, "README.md"), generateReadmeFile())];
|
|
637
639
|
let filesChanged = writeResults.filter(Boolean).length;
|
|
640
|
+
if (needsSqliteZeroSchema) {
|
|
641
|
+
const membership = dataMembershipFromLayout(layout);
|
|
642
|
+
const drizzleSchema = await generateDrizzleSchemaInputFileWithProject({
|
|
643
|
+
dir: baseDir,
|
|
644
|
+
schemaImportPath: "../../database/schema",
|
|
645
|
+
config
|
|
646
|
+
}, project);
|
|
647
|
+
const sqliteSchema = renderDrizzleZeroSqliteSchemaModule({
|
|
648
|
+
importPath: "./drizzleSchema",
|
|
649
|
+
tableNames: membership.allTables
|
|
650
|
+
});
|
|
651
|
+
if (writeFileIfChanged(resolve(generatedDir, "drizzleSchema.ts"), drizzleSchema)) {
|
|
652
|
+
filesChanged++;
|
|
653
|
+
}
|
|
654
|
+
if (writeFileIfChanged(resolve(generatedDir, "schema.ts"), sqliteSchema)) {
|
|
655
|
+
filesChanged++;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
638
658
|
let queryCount = 0;
|
|
639
659
|
let mutationCount = 0;
|
|
640
660
|
const typeToValibot = paramType => {
|
|
@@ -645,23 +665,12 @@ async function generate(options) {
|
|
|
645
665
|
}
|
|
646
666
|
};
|
|
647
667
|
const allQueries = [];
|
|
648
|
-
let queryResolver = null;
|
|
649
|
-
const getQueryResolver = () => {
|
|
650
|
-
if (!queryResolver) {
|
|
651
|
-
const allFiles = [...new Set(layout.namespaces.flatMap(namespace => namespace.sourcePaths))].map(path => ({
|
|
652
|
-
path,
|
|
653
|
-
content: readFileSync(path, "utf-8")
|
|
654
|
-
}));
|
|
655
|
-
queryResolver = createTypeResolver(ts, allFiles, baseDir);
|
|
656
|
-
}
|
|
657
|
-
return queryResolver;
|
|
658
|
-
};
|
|
659
668
|
for (const namespace of layout.namespaces.filter(namespace2 => namespace2.queryPath !== null)) {
|
|
660
669
|
const filePath = namespace.queryPath;
|
|
661
670
|
try {
|
|
662
|
-
const
|
|
663
|
-
const
|
|
664
|
-
|
|
671
|
+
const sourceFile = project.sourceFile(filePath);
|
|
672
|
+
const candidates = [];
|
|
673
|
+
sourceFile.forEachChild(node => {
|
|
665
674
|
if (ts.isVariableStatement(node)) {
|
|
666
675
|
const exportModifier = node.modifiers?.find(m => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
667
676
|
if (!exportModifier) return;
|
|
@@ -676,31 +685,33 @@ async function generate(options) {
|
|
|
676
685
|
const param = params[0];
|
|
677
686
|
paramType = param.type?.getText(sourceFile) || "unknown";
|
|
678
687
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
const resolvedType = resolveParamType(ts, resolver, resolverSourceFile, name, 0);
|
|
685
|
-
if (resolvedType) {
|
|
686
|
-
valibotCode = resolver.typeToValibot(resolvedType);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
if (valibotCode) {
|
|
691
|
-
allQueries.push({
|
|
692
|
-
name,
|
|
693
|
-
params: paramType,
|
|
694
|
-
valibotCode,
|
|
695
|
-
sourceFile: namespace.name,
|
|
696
|
-
importPath: namespaceImportPath(baseDir, filePath)
|
|
697
|
-
});
|
|
698
|
-
} else if (!silent && paramType !== "void") {
|
|
699
|
-
console.error(`\u2717 ${name}: could not resolve type "${paramType}"`);
|
|
700
|
-
}
|
|
688
|
+
candidates.push({
|
|
689
|
+
name,
|
|
690
|
+
paramType,
|
|
691
|
+
typeNode: params[0]?.type ?? null
|
|
692
|
+
});
|
|
701
693
|
}
|
|
702
694
|
}
|
|
703
695
|
});
|
|
696
|
+
const resolver = createTypeResolver(project.projectForFile(filePath));
|
|
697
|
+
for (const candidate of candidates) {
|
|
698
|
+
let valibotCode = typeToValibot(candidate.paramType);
|
|
699
|
+
if (!valibotCode && candidate.typeNode) {
|
|
700
|
+
const resolvedType = await resolveParamType(resolver, sourceFile, candidate.name, 0);
|
|
701
|
+
if (resolvedType) valibotCode = await resolver.typeToValibot(resolvedType);
|
|
702
|
+
}
|
|
703
|
+
if (valibotCode) {
|
|
704
|
+
allQueries.push({
|
|
705
|
+
name: candidate.name,
|
|
706
|
+
params: candidate.paramType,
|
|
707
|
+
valibotCode,
|
|
708
|
+
sourceFile: namespace.name,
|
|
709
|
+
importPath: namespaceImportPath(baseDir, filePath)
|
|
710
|
+
});
|
|
711
|
+
} else if (!silent && candidate.paramType !== "void") {
|
|
712
|
+
console.error(`\u2717 ${candidate.name}: could not resolve type "${candidate.paramType}"`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
704
715
|
} catch (err) {
|
|
705
716
|
if (!silent) console.error(`Error processing ${filePath}:`, err);
|
|
706
717
|
}
|
|
@@ -729,20 +740,14 @@ async function generate(options) {
|
|
|
729
740
|
if (aggregatesChanged) filesChanged++;
|
|
730
741
|
}
|
|
731
742
|
const allModelMutations = [];
|
|
732
|
-
const mutationFiles = [];
|
|
733
743
|
const unresolvedModels = [];
|
|
734
744
|
for (const namespace of modelNamespaces) {
|
|
735
745
|
const filePath = namespace.modelPath;
|
|
736
746
|
const fileBaseName = namespace.name;
|
|
737
747
|
try {
|
|
738
748
|
const content = readFileSync(filePath, "utf-8");
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
content,
|
|
742
|
-
baseName: fileBaseName
|
|
743
|
-
});
|
|
744
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
745
|
-
const result = extractMutationsFromModel(ts, sourceFile, content, filePath, !!silent, typeToValibot);
|
|
749
|
+
const sourceFile = project.sourceFile(filePath);
|
|
750
|
+
const result = extractMutationsFromModel(sourceFile, content, filePath, !!silent, typeToValibot);
|
|
746
751
|
if (result) {
|
|
747
752
|
result.modelName = fileBaseName;
|
|
748
753
|
allModelMutations.push(result);
|
|
@@ -759,36 +764,20 @@ async function generate(options) {
|
|
|
759
764
|
}
|
|
760
765
|
}
|
|
761
766
|
if (unresolvedModels.length > 0) {
|
|
762
|
-
const collectTsFiles = dir2 => {
|
|
763
|
-
const results = [];
|
|
764
|
-
for (const entry of readdirSync(dir2, {
|
|
765
|
-
withFileTypes: true
|
|
766
|
-
})) {
|
|
767
|
-
const fullPath = resolve(dir2, entry.name);
|
|
768
|
-
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
769
|
-
results.push(...collectTsFiles(fullPath));
|
|
770
|
-
} else if (entry.isFile() && isGeneratorSourceFile(entry.name)) {
|
|
771
|
-
results.push({
|
|
772
|
-
path: fullPath,
|
|
773
|
-
content: readFileSync(fullPath, "utf-8")
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
return results;
|
|
778
|
-
};
|
|
779
|
-
const allFiles = [...new Map(layout.sourceRoots.flatMap(collectTsFiles).map(file => [file.path, file])).values()];
|
|
780
|
-
const modelResolver = createTypeResolver(ts, allFiles, baseDir);
|
|
781
767
|
for (const {
|
|
782
768
|
baseName,
|
|
783
769
|
filePath
|
|
784
770
|
} of unresolvedModels) {
|
|
785
|
-
const
|
|
786
|
-
|
|
787
|
-
const resolvedTypes = resolveMutationParamTypes(
|
|
771
|
+
const sourceFile = project.sourceFile(filePath);
|
|
772
|
+
const modelResolver = createTypeResolver(project.projectForFile(filePath));
|
|
773
|
+
const resolvedTypes = await resolveMutationParamTypes(modelResolver, sourceFile);
|
|
788
774
|
if (resolvedTypes.size === 0) continue;
|
|
775
|
+
const resolvedValibot = /* @__PURE__ */new Map();
|
|
776
|
+
for (const [name, type] of resolvedTypes) {
|
|
777
|
+
resolvedValibot.set(name, await modelResolver.typeToValibot(type));
|
|
778
|
+
}
|
|
789
779
|
const content = readFileSync(filePath, "utf-8");
|
|
790
|
-
const
|
|
791
|
-
const result = extractMutationsFromModel(ts, sourceFile, content, filePath, !!silent, typeToValibot, resolvedTypes, modelResolver.typeToValibot);
|
|
780
|
+
const result = extractMutationsFromModel(sourceFile, content, filePath, !!silent, typeToValibot, resolvedValibot);
|
|
792
781
|
if (result) {
|
|
793
782
|
result.modelName = baseName;
|
|
794
783
|
const idx = allModelMutations.findIndex(m => m.modelName === baseName);
|
|
@@ -866,8 +855,13 @@ ${event} ${path}`);
|
|
|
866
855
|
}, debounce);
|
|
867
856
|
};
|
|
868
857
|
const databaseDir = resolve(dirname(baseDir), "database");
|
|
869
|
-
const
|
|
870
|
-
|
|
858
|
+
const project = await loadGeneratorProject(baseDir);
|
|
859
|
+
let layout;
|
|
860
|
+
try {
|
|
861
|
+
layout = discoverDataLayout(project, baseDir, options.config ? resolve(options.config) : void 0);
|
|
862
|
+
} finally {
|
|
863
|
+
await project.close();
|
|
864
|
+
}
|
|
871
865
|
const watcher = chokidar.watch([... /* @__PURE__ */new Set([...layout.sourceRoots, ...(existsSync(databaseDir) ? [databaseDir] : [])])], {
|
|
872
866
|
persistent: true,
|
|
873
867
|
ignoreInitial: true,
|