on-zero 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli.cjs +46 -41
- package/dist/cjs/cli.native.js +48 -43
- package/dist/cjs/cli.native.js.map +1 -1
- package/dist/cjs/constants.cjs +14 -12
- package/dist/cjs/constants.native.js +14 -12
- package/dist/cjs/constants.native.js.map +1 -1
- package/dist/cjs/createPermissions.cjs +66 -34
- package/dist/cjs/createPermissions.native.js +143 -87
- package/dist/cjs/createPermissions.native.js.map +1 -1
- package/dist/cjs/createSchemaFromDrizzle.cjs +15 -13
- package/dist/cjs/createSchemaFromDrizzle.native.js +15 -13
- package/dist/cjs/createSchemaFromDrizzle.native.js.map +1 -1
- package/dist/cjs/createUseQuery.cjs +48 -35
- package/dist/cjs/createUseQuery.native.js +52 -38
- package/dist/cjs/createUseQuery.native.js.map +1 -1
- package/dist/cjs/createZeroClient.cjs +177 -135
- package/dist/cjs/createZeroClient.native.js +246 -195
- package/dist/cjs/createZeroClient.native.js.map +1 -1
- package/dist/cjs/createZeroServer.cjs +175 -129
- package/dist/cjs/createZeroServer.native.js +170 -138
- package/dist/cjs/createZeroServer.native.js.map +1 -1
- package/dist/cjs/generate-helpers.cjs +122 -88
- package/dist/cjs/generate-helpers.native.js +209 -174
- package/dist/cjs/generate-helpers.native.js.map +1 -1
- package/dist/cjs/generate-lite.cjs +90 -58
- package/dist/cjs/generate-lite.native.js +200 -140
- package/dist/cjs/generate-lite.native.js.map +1 -1
- package/dist/cjs/generate-lite.test.cjs +229 -192
- package/dist/cjs/generate-lite.test.native.js +229 -194
- package/dist/cjs/generate-lite.test.native.js.map +1 -1
- package/dist/cjs/generate.cjs +455 -291
- package/dist/cjs/generate.native.js +747 -565
- package/dist/cjs/generate.native.js.map +1 -1
- package/dist/cjs/generate.test.cjs +170 -106
- package/dist/cjs/generate.test.native.js +171 -107
- package/dist/cjs/generate.test.native.js.map +1 -1
- package/dist/cjs/helpers/batchQuery.cjs +29 -18
- package/dist/cjs/helpers/batchQuery.native.js +36 -21
- package/dist/cjs/helpers/batchQuery.native.js.map +1 -1
- package/dist/cjs/helpers/clearZeroClientData.cjs +30 -21
- package/dist/cjs/helpers/clearZeroClientData.native.js +42 -33
- package/dist/cjs/helpers/clearZeroClientData.native.js.map +1 -1
- package/dist/cjs/helpers/createMutators.cjs +80 -42
- package/dist/cjs/helpers/createMutators.native.js +139 -87
- package/dist/cjs/helpers/createMutators.native.js.map +1 -1
- package/dist/cjs/helpers/didRunPermissionCheck.cjs +19 -13
- package/dist/cjs/helpers/didRunPermissionCheck.native.js +22 -20
- package/dist/cjs/helpers/didRunPermissionCheck.native.js.map +1 -1
- package/dist/cjs/helpers/ensureLoggedIn.cjs +16 -13
- package/dist/cjs/helpers/ensureLoggedIn.native.js +21 -18
- package/dist/cjs/helpers/ensureLoggedIn.native.js.map +1 -1
- package/dist/cjs/helpers/getAuth.cjs +25 -15
- package/dist/cjs/helpers/getAuth.native.js +25 -15
- package/dist/cjs/helpers/getAuth.native.js.map +1 -1
- package/dist/cjs/helpers/mutatorContext.cjs +21 -14
- package/dist/cjs/helpers/mutatorContext.native.js +21 -15
- package/dist/cjs/helpers/mutatorContext.native.js.map +1 -1
- package/dist/cjs/helpers/prettyFormatZeroQuery.cjs +126 -81
- package/dist/cjs/helpers/prettyFormatZeroQuery.native.js +135 -92
- package/dist/cjs/helpers/prettyFormatZeroQuery.native.js.map +1 -1
- package/dist/cjs/helpers/queryContext.cjs +12 -10
- package/dist/cjs/helpers/queryContext.native.js +16 -13
- package/dist/cjs/helpers/queryContext.native.js.map +1 -1
- package/dist/cjs/helpers/showZeroClientError.cjs +24 -19
- package/dist/cjs/helpers/showZeroClientError.native.js +38 -34
- package/dist/cjs/helpers/showZeroClientError.native.js.map +1 -1
- package/dist/cjs/helpers/useZeroDebug.cjs +82 -49
- package/dist/cjs/helpers/useZeroDebug.native.js +83 -55
- package/dist/cjs/helpers/useZeroDebug.native.js.map +1 -1
- package/dist/cjs/index.cjs +17 -15
- package/dist/cjs/index.native.js +17 -15
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/modelRegistry.cjs +12 -10
- package/dist/cjs/modelRegistry.native.js +12 -10
- package/dist/cjs/modelRegistry.native.js.map +1 -1
- package/dist/cjs/mutations.cjs +66 -42
- package/dist/cjs/mutations.native.js +68 -46
- package/dist/cjs/mutations.native.js.map +1 -1
- package/dist/cjs/queryRegistry.cjs +13 -10
- package/dist/cjs/queryRegistry.native.js +14 -11
- package/dist/cjs/queryRegistry.native.js.map +1 -1
- package/dist/cjs/resolveQuery.cjs +22 -18
- package/dist/cjs/resolveQuery.native.js +32 -28
- package/dist/cjs/resolveQuery.native.js.map +1 -1
- package/dist/cjs/run.cjs +35 -28
- package/dist/cjs/run.native.js +35 -29
- package/dist/cjs/run.native.js.map +1 -1
- package/dist/cjs/server.cjs +7 -5
- package/dist/cjs/serverWhere.cjs +13 -11
- package/dist/cjs/serverWhere.native.js +13 -11
- package/dist/cjs/serverWhere.native.js.map +1 -1
- package/dist/cjs/serverWhere.test.cjs +83 -55
- package/dist/cjs/serverWhere.test.native.js +72 -50
- package/dist/cjs/serverWhere.test.native.js.map +1 -1
- package/dist/cjs/state.cjs +49 -44
- package/dist/cjs/state.native.js +56 -53
- package/dist/cjs/state.native.js.map +1 -1
- package/dist/cjs/types.cjs +7 -5
- package/dist/cjs/types.native.js +7 -5
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/usePermission.test.cjs +58 -45
- package/dist/cjs/usePermission.test.native.js +59 -48
- package/dist/cjs/usePermission.test.native.js.map +1 -1
- package/dist/cjs/vite-plugin.cjs +41 -21
- package/dist/cjs/vite-plugin.native.js +61 -47
- package/dist/cjs/vite-plugin.native.js.map +1 -1
- package/dist/cjs/where.cjs +39 -24
- package/dist/cjs/where.native.js +44 -29
- package/dist/cjs/where.native.js.map +1 -1
- package/dist/cjs/zeroRunner.cjs +18 -12
- package/dist/cjs/zeroRunner.native.js +22 -16
- package/dist/cjs/zeroRunner.native.js.map +1 -1
- package/dist/cjs/zql.cjs +14 -11
- package/dist/cjs/zql.native.js +19 -17
- package/dist/cjs/zql.native.js.map +1 -1
- package/dist/esm/cli.mjs +43 -38
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/cli.native.js +44 -39
- package/dist/esm/cli.native.js.map +1 -1
- package/dist/esm/constants.mjs +2 -2
- package/dist/esm/constants.mjs.map +1 -1
- package/dist/esm/constants.native.js +2 -2
- package/dist/esm/constants.native.js.map +1 -1
- package/dist/esm/createPermissions.mjs +48 -18
- package/dist/esm/createPermissions.mjs.map +1 -1
- package/dist/esm/createPermissions.native.js +125 -71
- package/dist/esm/createPermissions.native.js.map +1 -1
- package/dist/esm/createUseQuery.mjs +32 -21
- package/dist/esm/createUseQuery.mjs.map +1 -1
- package/dist/esm/createUseQuery.native.js +36 -24
- package/dist/esm/createUseQuery.native.js.map +1 -1
- package/dist/esm/createZeroClient.mjs +148 -108
- package/dist/esm/createZeroClient.mjs.map +1 -1
- package/dist/esm/createZeroClient.native.js +217 -168
- package/dist/esm/createZeroClient.native.js.map +1 -1
- package/dist/esm/createZeroServer.mjs +148 -104
- package/dist/esm/createZeroServer.mjs.map +1 -1
- package/dist/esm/createZeroServer.native.js +143 -113
- package/dist/esm/createZeroServer.native.js.map +1 -1
- package/dist/esm/generate-helpers.mjs +110 -78
- package/dist/esm/generate-helpers.mjs.map +1 -1
- package/dist/esm/generate-helpers.native.js +197 -164
- package/dist/esm/generate-helpers.native.js.map +1 -1
- package/dist/esm/generate-lite.mjs +78 -48
- package/dist/esm/generate-lite.mjs.map +1 -1
- package/dist/esm/generate-lite.native.js +188 -130
- package/dist/esm/generate-lite.native.js.map +1 -1
- package/dist/esm/generate-lite.test.mjs +227 -190
- package/dist/esm/generate-lite.test.mjs.map +1 -1
- package/dist/esm/generate-lite.test.native.js +227 -192
- package/dist/esm/generate-lite.test.native.js.map +1 -1
- package/dist/esm/generate.mjs +427 -265
- package/dist/esm/generate.mjs.map +1 -1
- package/dist/esm/generate.native.js +718 -538
- package/dist/esm/generate.native.js.map +1 -1
- package/dist/esm/generate.test.mjs +165 -101
- package/dist/esm/generate.test.mjs.map +1 -1
- package/dist/esm/generate.test.native.js +165 -101
- package/dist/esm/generate.test.native.js.map +1 -1
- package/dist/esm/helpers/batchQuery.mjs +17 -8
- package/dist/esm/helpers/batchQuery.mjs.map +1 -1
- package/dist/esm/helpers/batchQuery.native.js +24 -11
- package/dist/esm/helpers/batchQuery.native.js.map +1 -1
- package/dist/esm/helpers/clearZeroClientData.mjs +18 -11
- package/dist/esm/helpers/clearZeroClientData.mjs.map +1 -1
- package/dist/esm/helpers/clearZeroClientData.native.js +30 -23
- package/dist/esm/helpers/clearZeroClientData.native.js.map +1 -1
- package/dist/esm/helpers/createMutators.mjs +53 -17
- package/dist/esm/helpers/createMutators.mjs.map +1 -1
- package/dist/esm/helpers/createMutators.native.js +112 -62
- package/dist/esm/helpers/createMutators.native.js.map +1 -1
- package/dist/esm/helpers/didRunPermissionCheck.mjs +7 -3
- package/dist/esm/helpers/didRunPermissionCheck.mjs.map +1 -1
- package/dist/esm/helpers/didRunPermissionCheck.native.js +9 -9
- package/dist/esm/helpers/didRunPermissionCheck.native.js.map +1 -1
- package/dist/esm/helpers/ensureLoggedIn.mjs +2 -1
- package/dist/esm/helpers/ensureLoggedIn.mjs.map +1 -1
- package/dist/esm/helpers/ensureLoggedIn.native.js +2 -1
- package/dist/esm/helpers/ensureLoggedIn.native.js.map +1 -1
- package/dist/esm/helpers/getAuth.mjs +10 -2
- package/dist/esm/helpers/getAuth.mjs.map +1 -1
- package/dist/esm/helpers/getAuth.native.js +10 -2
- package/dist/esm/helpers/getAuth.native.js.map +1 -1
- package/dist/esm/helpers/mutatorContext.mjs +9 -4
- package/dist/esm/helpers/mutatorContext.mjs.map +1 -1
- package/dist/esm/helpers/mutatorContext.native.js +8 -4
- package/dist/esm/helpers/mutatorContext.native.js.map +1 -1
- package/dist/esm/helpers/prettyFormatZeroQuery.mjs +114 -71
- package/dist/esm/helpers/prettyFormatZeroQuery.mjs.map +1 -1
- package/dist/esm/helpers/prettyFormatZeroQuery.native.js +121 -80
- package/dist/esm/helpers/prettyFormatZeroQuery.native.js.map +1 -1
- package/dist/esm/helpers/queryContext.native.js +2 -1
- package/dist/esm/helpers/queryContext.native.js.map +1 -1
- package/dist/esm/helpers/showZeroClientError.mjs +12 -9
- package/dist/esm/helpers/showZeroClientError.mjs.map +1 -1
- package/dist/esm/helpers/showZeroClientError.native.js +25 -23
- package/dist/esm/helpers/showZeroClientError.native.js.map +1 -1
- package/dist/esm/helpers/useZeroDebug.mjs +67 -36
- package/dist/esm/helpers/useZeroDebug.mjs.map +1 -1
- package/dist/esm/helpers/useZeroDebug.native.js +68 -42
- package/dist/esm/helpers/useZeroDebug.native.js.map +1 -1
- package/dist/esm/mutations.mjs +51 -29
- package/dist/esm/mutations.mjs.map +1 -1
- package/dist/esm/mutations.native.js +53 -33
- package/dist/esm/mutations.native.js.map +1 -1
- package/dist/esm/queryRegistry.mjs +1 -0
- package/dist/esm/queryRegistry.mjs.map +1 -1
- package/dist/esm/queryRegistry.native.js +2 -1
- package/dist/esm/queryRegistry.native.js.map +1 -1
- package/dist/esm/resolveQuery.mjs +10 -8
- package/dist/esm/resolveQuery.mjs.map +1 -1
- package/dist/esm/resolveQuery.native.js +20 -18
- package/dist/esm/resolveQuery.native.js.map +1 -1
- package/dist/esm/run.mjs +21 -16
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/run.native.js +20 -16
- package/dist/esm/run.native.js.map +1 -1
- package/dist/esm/serverWhere.mjs +1 -1
- package/dist/esm/serverWhere.mjs.map +1 -1
- package/dist/esm/serverWhere.native.js +1 -1
- package/dist/esm/serverWhere.native.js.map +1 -1
- package/dist/esm/serverWhere.test.mjs +79 -51
- package/dist/esm/serverWhere.test.mjs.map +1 -1
- package/dist/esm/serverWhere.test.native.js +68 -46
- package/dist/esm/serverWhere.test.native.js.map +1 -1
- package/dist/esm/state.mjs +35 -32
- package/dist/esm/state.mjs.map +1 -1
- package/dist/esm/state.native.js +41 -40
- package/dist/esm/state.native.js.map +1 -1
- package/dist/esm/usePermission.test.mjs +53 -40
- package/dist/esm/usePermission.test.mjs.map +1 -1
- package/dist/esm/usePermission.test.native.js +54 -43
- package/dist/esm/usePermission.test.native.js.map +1 -1
- package/dist/esm/vite-plugin.mjs +27 -9
- package/dist/esm/vite-plugin.mjs.map +1 -1
- package/dist/esm/vite-plugin.native.js +47 -35
- package/dist/esm/vite-plugin.native.js.map +1 -1
- package/dist/esm/where.mjs +24 -11
- package/dist/esm/where.mjs.map +1 -1
- package/dist/esm/where.native.js +29 -16
- package/dist/esm/where.native.js.map +1 -1
- package/dist/esm/zeroRunner.mjs +6 -2
- package/dist/esm/zeroRunner.mjs.map +1 -1
- package/dist/esm/zeroRunner.native.js +8 -4
- package/dist/esm/zeroRunner.native.js.map +1 -1
- package/dist/esm/zql.mjs +2 -1
- package/dist/esm/zql.mjs.map +1 -1
- package/dist/esm/zql.native.js.map +1 -1
- package/package.json +3 -3
package/dist/esm/generate.mjs
CHANGED
|
@@ -3,17 +3,20 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from
|
|
|
3
3
|
import { basename, dirname, resolve } from "node:path";
|
|
4
4
|
import { formatObjectKey, generateGroupedQueriesFile, generateModelsFile, generateReadmeFile, generateSyncedMutationsFile, generateSyncedQueriesFile, generateTablesFile, generateTypesFile, parseColumnType, parseTypeString, shouldSkipObjectKey } from "./generate-helpers.mjs";
|
|
5
5
|
const hash = s => createHash("sha256").update(s).digest("hex");
|
|
6
|
-
let generateCache = {}
|
|
7
|
-
|
|
6
|
+
let generateCache = {};
|
|
7
|
+
let generateCachePath = "";
|
|
8
8
|
function getCacheDir() {
|
|
9
9
|
let dir = process.cwd();
|
|
10
|
-
|
|
10
|
+
while (dir !== "/") {
|
|
11
11
|
const nm = resolve(dir, "node_modules");
|
|
12
12
|
if (existsSync(nm)) {
|
|
13
13
|
const cacheDir = resolve(nm, ".on-zero");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
if (!existsSync(cacheDir)) {
|
|
15
|
+
mkdirSync(cacheDir, {
|
|
16
|
+
recursive: true
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return cacheDir;
|
|
17
20
|
}
|
|
18
21
|
dir = resolve(dir, "..");
|
|
19
22
|
}
|
|
@@ -21,22 +24,28 @@ function getCacheDir() {
|
|
|
21
24
|
}
|
|
22
25
|
function loadCache() {
|
|
23
26
|
const cacheDir = getCacheDir();
|
|
24
|
-
if (cacheDir)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
27
|
+
if (!cacheDir) return;
|
|
28
|
+
generateCachePath = resolve(cacheDir, "generate-cache.json");
|
|
29
|
+
try {
|
|
30
|
+
generateCache = JSON.parse(readFileSync(generateCachePath, "utf-8"));
|
|
31
|
+
} catch {
|
|
32
|
+
generateCache = {};
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
function saveCache() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
if (generateCachePath) {
|
|
37
|
+
writeFileSync(generateCachePath, JSON.stringify(generateCache) + "\n", "utf-8");
|
|
38
|
+
}
|
|
36
39
|
}
|
|
37
40
|
function writeFileIfChanged(filePath, content) {
|
|
38
41
|
const contentHash = hash(content);
|
|
39
|
-
|
|
42
|
+
const cachedHash = generateCache[filePath];
|
|
43
|
+
if (cachedHash === contentHash && existsSync(filePath)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
writeFileSync(filePath, content, "utf-8");
|
|
47
|
+
generateCache[filePath] = contentHash;
|
|
48
|
+
return true;
|
|
40
49
|
}
|
|
41
50
|
function createTypeResolver(ts, files, dir) {
|
|
42
51
|
const configPath = ts.findConfigFile(dir, ts.sys.fileExists, "tsconfig.json");
|
|
@@ -44,9 +53,9 @@ function createTypeResolver(ts, files, dir) {
|
|
|
44
53
|
target: ts.ScriptTarget.Latest,
|
|
45
54
|
module: ts.ModuleKind.ESNext,
|
|
46
55
|
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
47
|
-
strict:
|
|
48
|
-
skipLibCheck:
|
|
49
|
-
noEmit:
|
|
56
|
+
strict: false,
|
|
57
|
+
skipLibCheck: true,
|
|
58
|
+
noEmit: true
|
|
50
59
|
};
|
|
51
60
|
if (configPath) {
|
|
52
61
|
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
@@ -59,15 +68,22 @@ function createTypeResolver(ts, files, dir) {
|
|
|
59
68
|
}
|
|
60
69
|
}
|
|
61
70
|
const fileMap = /* @__PURE__ */new Map();
|
|
62
|
-
for (const f of files)
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
for (const f of files) {
|
|
72
|
+
fileMap.set(f.path, f.content);
|
|
73
|
+
}
|
|
74
|
+
const host = ts.createCompilerHost(compilerOptions);
|
|
75
|
+
const originalGetSourceFile = host.getSourceFile.bind(host);
|
|
65
76
|
host.getSourceFile = (fileName, languageVersion, onError) => {
|
|
66
77
|
const content = fileMap.get(fileName);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
if (content !== void 0) {
|
|
79
|
+
return ts.createSourceFile(fileName, content, languageVersion, true);
|
|
80
|
+
}
|
|
81
|
+
return originalGetSourceFile(fileName, languageVersion, onError);
|
|
82
|
+
};
|
|
83
|
+
host.fileExists = fileName => fileMap.has(fileName) || ts.sys.fileExists(fileName);
|
|
84
|
+
host.readFile = fileName => fileMap.get(fileName) ?? ts.sys.readFile(fileName);
|
|
85
|
+
const program = ts.createProgram(files.map(f => f.path), compilerOptions, host);
|
|
86
|
+
const checker = program.getTypeChecker();
|
|
71
87
|
return {
|
|
72
88
|
program,
|
|
73
89
|
checker,
|
|
@@ -87,102 +103,146 @@ function createTypeResolver(ts, files, dir) {
|
|
|
87
103
|
}
|
|
88
104
|
function resolveParamType(ts, resolver, sourceFile, exportName, paramIndex) {
|
|
89
105
|
let result = null;
|
|
90
|
-
|
|
91
|
-
if (result
|
|
106
|
+
ts.forEachChild(sourceFile, node => {
|
|
107
|
+
if (result) return;
|
|
108
|
+
if (!ts.isVariableStatement(node)) return;
|
|
109
|
+
if (!node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) return;
|
|
92
110
|
const decl = node.declarationList.declarations[0];
|
|
93
|
-
if (!
|
|
111
|
+
if (!decl || !ts.isVariableDeclaration(decl)) return;
|
|
112
|
+
if (decl.name.getText(sourceFile) !== exportName) return;
|
|
113
|
+
if (decl.initializer && ts.isArrowFunction(decl.initializer)) {
|
|
94
114
|
const param = decl.initializer.parameters[paramIndex];
|
|
95
|
-
|
|
115
|
+
if (param?.type) {
|
|
116
|
+
result = resolver.resolveType(param.type);
|
|
117
|
+
}
|
|
96
118
|
}
|
|
97
|
-
})
|
|
119
|
+
});
|
|
120
|
+
return result;
|
|
98
121
|
}
|
|
99
122
|
function resolveMutationParamTypes(ts, resolver, sourceFile) {
|
|
100
123
|
const resolved = /* @__PURE__ */new Map();
|
|
101
|
-
|
|
102
|
-
if (!ts.isVariableStatement(node)
|
|
124
|
+
ts.forEachChild(sourceFile, node => {
|
|
125
|
+
if (!ts.isVariableStatement(node)) return;
|
|
126
|
+
if (!node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) return;
|
|
103
127
|
const decl = node.declarationList.declarations[0];
|
|
104
|
-
if (!decl || !ts.isVariableDeclaration(decl)
|
|
128
|
+
if (!decl || !ts.isVariableDeclaration(decl)) return;
|
|
129
|
+
if (decl.name.getText(sourceFile) !== "mutate") return;
|
|
130
|
+
if (!decl.initializer || !ts.isCallExpression(decl.initializer)) return;
|
|
105
131
|
const args = decl.initializer.arguments;
|
|
106
132
|
let handlersArg = null;
|
|
107
|
-
for (let i = args.length - 1; i >= 0; i--)
|
|
108
|
-
|
|
109
|
-
|
|
133
|
+
for (let i = args.length - 1; i >= 0; i--) {
|
|
134
|
+
if (ts.isObjectLiteralExpression(args[i])) {
|
|
135
|
+
handlersArg = args[i];
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
110
138
|
}
|
|
111
|
-
if (handlersArg)
|
|
139
|
+
if (!handlersArg) return;
|
|
140
|
+
for (const prop of handlersArg.properties) {
|
|
112
141
|
if (!ts.isPropertyAssignment(prop) && !ts.isMethodDeclaration(prop)) continue;
|
|
113
142
|
const name = prop.name?.getText(sourceFile);
|
|
114
143
|
if (!name) continue;
|
|
115
144
|
let params = null;
|
|
116
145
|
if (ts.isPropertyAssignment(prop)) {
|
|
117
146
|
const init = prop.initializer;
|
|
118
|
-
(ts.isArrowFunction(init) || ts.isFunctionExpression(init))
|
|
119
|
-
|
|
147
|
+
if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
|
|
148
|
+
params = init.parameters;
|
|
149
|
+
}
|
|
150
|
+
} else if (ts.isMethodDeclaration(prop)) {
|
|
151
|
+
params = prop.parameters;
|
|
152
|
+
}
|
|
120
153
|
if (!params || params.length < 2) continue;
|
|
121
154
|
const typeNode = params[1].type;
|
|
122
155
|
if (!typeNode) continue;
|
|
123
156
|
const expanded = resolver.resolveType(typeNode);
|
|
124
|
-
|
|
157
|
+
if (expanded) {
|
|
158
|
+
resolved.set(name, expanded);
|
|
159
|
+
}
|
|
125
160
|
}
|
|
126
|
-
})
|
|
161
|
+
});
|
|
162
|
+
return resolved;
|
|
127
163
|
}
|
|
128
164
|
function extractMutationsFromModel(ts, sourceFile, content, fileName, silent, typeToValibot, resolvedTypes, resolvedTypeToValibot) {
|
|
129
165
|
let mutateNode = null;
|
|
130
|
-
|
|
131
|
-
if (!ts.isVariableStatement(node)
|
|
166
|
+
ts.forEachChild(sourceFile, node => {
|
|
167
|
+
if (!ts.isVariableStatement(node)) return;
|
|
168
|
+
if (!node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) return;
|
|
132
169
|
const decl = node.declarationList.declarations[0];
|
|
133
|
-
!decl || !ts.isVariableDeclaration(decl)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
if (!decl || !ts.isVariableDeclaration(decl)) return;
|
|
171
|
+
if (decl.name.getText(sourceFile) !== "mutate") return;
|
|
172
|
+
if (decl.initializer && ts.isCallExpression(decl.initializer)) {
|
|
173
|
+
mutateNode = decl.initializer;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
if (!mutateNode) {
|
|
177
|
+
return {
|
|
178
|
+
modelName: basename(fileName, ".ts"),
|
|
179
|
+
hasCRUD: false,
|
|
180
|
+
columns: {},
|
|
181
|
+
primaryKeys: [],
|
|
182
|
+
custom: []
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const call = mutateNode;
|
|
186
|
+
const args = call.arguments;
|
|
187
|
+
const hasCRUD = args.length >= 2;
|
|
143
188
|
let handlersArg = null;
|
|
144
|
-
args.length === 1 && ts.isObjectLiteralExpression(args[0])
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
189
|
+
if (args.length === 1 && ts.isObjectLiteralExpression(args[0])) {
|
|
190
|
+
handlersArg = args[0];
|
|
191
|
+
} else if (args.length === 3 && ts.isObjectLiteralExpression(args[2])) {
|
|
192
|
+
handlersArg = args[2];
|
|
193
|
+
}
|
|
194
|
+
const columns = {};
|
|
195
|
+
const primaryKeys = [];
|
|
196
|
+
if (hasCRUD) {
|
|
197
|
+
extractSchemaColumns(ts, sourceFile, columns, primaryKeys);
|
|
198
|
+
}
|
|
148
199
|
const custom = [];
|
|
149
|
-
if (handlersArg)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
200
|
+
if (handlersArg) {
|
|
201
|
+
for (const prop of handlersArg.properties) {
|
|
202
|
+
if (!ts.isPropertyAssignment(prop) && !ts.isMethodDeclaration(prop)) continue;
|
|
203
|
+
const name = prop.name?.getText(sourceFile);
|
|
204
|
+
if (!name) continue;
|
|
205
|
+
let params = null;
|
|
206
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
207
|
+
const init = prop.initializer;
|
|
208
|
+
if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
|
|
209
|
+
params = init.parameters;
|
|
210
|
+
}
|
|
211
|
+
} else if (ts.isMethodDeclaration(prop)) {
|
|
212
|
+
params = prop.parameters;
|
|
213
|
+
}
|
|
214
|
+
if (!params) continue;
|
|
215
|
+
if (params.length < 2) {
|
|
216
|
+
custom.push({
|
|
217
|
+
name,
|
|
218
|
+
paramType: "void",
|
|
219
|
+
valibotCode: ""
|
|
220
|
+
});
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const secondParam = params[1];
|
|
224
|
+
const paramType = secondParam.type?.getText(sourceFile) || "unknown";
|
|
225
|
+
if (paramType === "unknown") {
|
|
226
|
+
custom.push({
|
|
227
|
+
name,
|
|
228
|
+
paramType: "unknown",
|
|
229
|
+
valibotCode: ""
|
|
230
|
+
});
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
let valibotCode = typeToValibot(paramType);
|
|
234
|
+
if (!valibotCode && resolvedTypes && resolvedTypeToValibot) {
|
|
235
|
+
const resolvedType = resolvedTypes.get(name);
|
|
236
|
+
if (resolvedType) {
|
|
237
|
+
valibotCode = resolvedTypeToValibot(resolvedType);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
169
240
|
custom.push({
|
|
170
241
|
name,
|
|
171
|
-
paramType
|
|
172
|
-
valibotCode: ""
|
|
242
|
+
paramType,
|
|
243
|
+
valibotCode: valibotCode || ""
|
|
173
244
|
});
|
|
174
|
-
continue;
|
|
175
245
|
}
|
|
176
|
-
let valibotCode = typeToValibot(paramType);
|
|
177
|
-
if (!valibotCode && resolvedTypes && resolvedTypeToValibot) {
|
|
178
|
-
const resolvedType = resolvedTypes.get(name);
|
|
179
|
-
resolvedType && (valibotCode = resolvedTypeToValibot(resolvedType));
|
|
180
|
-
}
|
|
181
|
-
custom.push({
|
|
182
|
-
name,
|
|
183
|
-
paramType,
|
|
184
|
-
valibotCode: valibotCode || ""
|
|
185
|
-
});
|
|
186
246
|
}
|
|
187
247
|
return {
|
|
188
248
|
modelName: "",
|
|
@@ -196,16 +256,24 @@ function extractSchemaColumns(ts, sourceFile, columns, primaryKeys) {
|
|
|
196
256
|
function visit(node) {
|
|
197
257
|
if (ts.isCallExpression(node)) {
|
|
198
258
|
const text = node.expression.getText(sourceFile);
|
|
199
|
-
if (text.endsWith(".primaryKey"))
|
|
259
|
+
if (text.endsWith(".primaryKey")) {
|
|
260
|
+
for (const arg of node.arguments) {
|
|
261
|
+
if (ts.isStringLiteral(arg)) {
|
|
262
|
+
primaryKeys.push(arg.text);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
200
266
|
if (text.endsWith(".columns") && node.arguments.length === 1) {
|
|
201
267
|
const obj = node.arguments[0];
|
|
202
|
-
if (ts.isObjectLiteralExpression(obj))
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
268
|
+
if (ts.isObjectLiteralExpression(obj)) {
|
|
269
|
+
for (const prop of obj.properties) {
|
|
270
|
+
if (!ts.isPropertyAssignment(prop)) continue;
|
|
271
|
+
const colName = prop.name?.getText(sourceFile);
|
|
272
|
+
if (!colName) continue;
|
|
273
|
+
const initText = prop.initializer.getText(sourceFile);
|
|
274
|
+
const colType = parseColumnType(initText);
|
|
275
|
+
columns[colName] = colType;
|
|
276
|
+
}
|
|
209
277
|
}
|
|
210
278
|
}
|
|
211
279
|
}
|
|
@@ -214,7 +282,7 @@ function extractSchemaColumns(ts, sourceFile, columns, primaryKeys) {
|
|
|
214
282
|
visit(sourceFile);
|
|
215
283
|
}
|
|
216
284
|
function tsTypeToValibot(ts, checker, type, seen) {
|
|
217
|
-
|
|
285
|
+
if (!seen) seen = /* @__PURE__ */new Set();
|
|
218
286
|
const flags = type.getFlags();
|
|
219
287
|
if (flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection)) {
|
|
220
288
|
if (seen.has(type)) return "v.unknown()";
|
|
@@ -228,23 +296,38 @@ function tsTypeToValibot(ts, checker, type, seen) {
|
|
|
228
296
|
if (flags & ts.TypeFlags.Null) return "v.null_()";
|
|
229
297
|
if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) return "v.unknown()";
|
|
230
298
|
if (flags & ts.TypeFlags.Never) return "v.never()";
|
|
231
|
-
if (flags & ts.TypeFlags.StringLiteral)
|
|
232
|
-
|
|
233
|
-
|
|
299
|
+
if (flags & ts.TypeFlags.StringLiteral) {
|
|
300
|
+
return `v.literal(${JSON.stringify(type.value)})`;
|
|
301
|
+
}
|
|
302
|
+
if (flags & ts.TypeFlags.NumberLiteral) {
|
|
303
|
+
return `v.literal(${type.value})`;
|
|
304
|
+
}
|
|
305
|
+
if (flags & ts.TypeFlags.BooleanLiteral) {
|
|
306
|
+
const name = type.intrinsicName;
|
|
307
|
+
return `v.literal(${name === "true"})`;
|
|
308
|
+
}
|
|
234
309
|
if (type.isUnion()) {
|
|
235
|
-
const members = type.types
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
310
|
+
const members = type.types;
|
|
311
|
+
const hasNull = members.some(t => t.getFlags() & ts.TypeFlags.Null);
|
|
312
|
+
const hasUndefined = members.some(t => t.getFlags() & (ts.TypeFlags.Undefined | ts.TypeFlags.Void));
|
|
313
|
+
const rest = members.filter(t => !(t.getFlags() & (ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void)));
|
|
239
314
|
if (rest.length === 2 && rest.every(t => t.getFlags() & ts.TypeFlags.BooleanLiteral)) {
|
|
240
315
|
let inner2 = "v.boolean()";
|
|
241
|
-
|
|
316
|
+
if (hasNull) inner2 = `v.nullable(${inner2})`;
|
|
317
|
+
if (hasUndefined) inner2 = `v.optional(${inner2})`;
|
|
318
|
+
return inner2;
|
|
242
319
|
}
|
|
243
320
|
if (rest.length === 0) return "v.unknown()";
|
|
244
321
|
let inner = rest.length === 1 ? recurse(rest[0]) : `v.union([${rest.map(t => recurse(t)).join(", ")}])`;
|
|
245
|
-
|
|
322
|
+
if (hasNull) inner = `v.nullable(${inner})`;
|
|
323
|
+
if (hasUndefined) inner = `v.optional(${inner})`;
|
|
324
|
+
return inner;
|
|
246
325
|
}
|
|
247
|
-
const resolveSymbolType = prop =>
|
|
326
|
+
const resolveSymbolType = prop => {
|
|
327
|
+
if (prop.valueDeclaration) return checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
|
|
328
|
+
if (prop.declarations?.[0]) return checker.getTypeOfSymbolAtLocation(prop, prop.declarations[0]);
|
|
329
|
+
return checker.getDeclaredTypeOfSymbol(prop);
|
|
330
|
+
};
|
|
248
331
|
if (type.isIntersection()) {
|
|
249
332
|
const props2 = type.getProperties();
|
|
250
333
|
if (props2.length === 0) return "v.object({})";
|
|
@@ -252,69 +335,98 @@ function tsTypeToValibot(ts, checker, type, seen) {
|
|
|
252
335
|
for (const prop of props2) {
|
|
253
336
|
const name = prop.getName();
|
|
254
337
|
if (shouldSkipObjectKey(name)) continue;
|
|
255
|
-
const propType = resolveSymbolType(prop)
|
|
256
|
-
|
|
338
|
+
const propType = resolveSymbolType(prop);
|
|
339
|
+
const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional);
|
|
257
340
|
let val = recurse(propType);
|
|
258
|
-
isOptional && !val.startsWith("v.optional(")
|
|
341
|
+
if (isOptional && !val.startsWith("v.optional(")) {
|
|
342
|
+
val = `v.optional(${val})`;
|
|
343
|
+
}
|
|
344
|
+
entries.push(`${formatObjectKey(name)}: ${val}`);
|
|
259
345
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
346
|
+
if (entries.length === 0) return "v.object({})";
|
|
347
|
+
return `v.object({
|
|
348
|
+
${entries.join(",\n ")},
|
|
263
349
|
})`;
|
|
264
350
|
}
|
|
265
351
|
const props = type.getProperties();
|
|
266
352
|
if (props.length > 0 && (type.getFlags() & ts.TypeFlags.Object || type.objectFlags)) {
|
|
267
353
|
const objectFlags = type.objectFlags ?? 0;
|
|
268
354
|
if (objectFlags & ts.ObjectFlags.Reference) {
|
|
269
|
-
const typeRef = type
|
|
270
|
-
|
|
271
|
-
|
|
355
|
+
const typeRef = type;
|
|
356
|
+
const symbol = type.getSymbol();
|
|
357
|
+
const name = symbol?.getName();
|
|
358
|
+
if ((name === "Array" || name === "ReadonlyArray") && typeRef.typeArguments?.length === 1) {
|
|
359
|
+
return `v.array(${recurse(typeRef.typeArguments[0])})`;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (objectFlags & ts.ObjectFlags.Tuple) {
|
|
363
|
+
const typeRef = type;
|
|
364
|
+
const typeArgs = typeRef.typeArguments || [];
|
|
365
|
+
return `v.tuple([${typeArgs.map(t => recurse(t)).join(", ")}])`;
|
|
272
366
|
}
|
|
273
|
-
if (objectFlags & ts.ObjectFlags.Tuple) return `v.tuple([${(type.typeArguments || []).map(t => recurse(t)).join(", ")}])`;
|
|
274
367
|
const entries = [];
|
|
275
368
|
for (const prop of props) {
|
|
276
369
|
const name = prop.getName();
|
|
277
370
|
if (shouldSkipObjectKey(name)) continue;
|
|
278
|
-
const propType = resolveSymbolType(prop)
|
|
279
|
-
|
|
371
|
+
const propType = resolveSymbolType(prop);
|
|
372
|
+
const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional);
|
|
280
373
|
let val = recurse(propType);
|
|
281
|
-
isOptional && !val.startsWith("v.optional(")
|
|
374
|
+
if (isOptional && !val.startsWith("v.optional(")) {
|
|
375
|
+
val = `v.optional(${val})`;
|
|
376
|
+
}
|
|
377
|
+
entries.push(`${formatObjectKey(name)}: ${val}`);
|
|
282
378
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
379
|
+
if (entries.length === 0) return "v.object({})";
|
|
380
|
+
return `v.object({
|
|
381
|
+
${entries.join(",\n ")},
|
|
286
382
|
})`;
|
|
287
383
|
}
|
|
288
384
|
const stringIndex = type.getStringIndexType();
|
|
289
|
-
if (stringIndex)
|
|
385
|
+
if (stringIndex) {
|
|
386
|
+
return `v.record(v.string(), ${recurse(stringIndex)})`;
|
|
387
|
+
}
|
|
290
388
|
const numberIndex = type.getNumberIndexType();
|
|
291
|
-
|
|
389
|
+
if (numberIndex) {
|
|
390
|
+
return `v.record(v.number(), ${recurse(numberIndex)})`;
|
|
391
|
+
}
|
|
392
|
+
return "v.unknown()";
|
|
292
393
|
}
|
|
293
394
|
function serializeColumnBuilder(col) {
|
|
294
|
-
|
|
295
|
-
|
|
395
|
+
const zeroType = col.type === "string" ? "string" : col.type === "number" ? "number" : col.type === "boolean" ? "boolean" : "json";
|
|
396
|
+
let expr = `${zeroType}()`;
|
|
397
|
+
if (col.serverName) {
|
|
398
|
+
expr += `.from('${col.serverName}')`;
|
|
399
|
+
}
|
|
400
|
+
if (col.optional) {
|
|
401
|
+
expr += ".optional()";
|
|
402
|
+
}
|
|
403
|
+
return expr;
|
|
296
404
|
}
|
|
297
405
|
function generateDrizzleSchemaFile(schema) {
|
|
298
|
-
const lines = [
|
|
299
|
-
|
|
406
|
+
const lines = [`// auto-generated by: on-zero generate (from drizzle schema)`, `import { boolean, createSchema, json, number, relationships, string, table } from '@rocicorp/zero'`, ``];
|
|
407
|
+
const tableNames = Object.keys(schema.tables).sort();
|
|
300
408
|
for (const tableName of tableNames) {
|
|
301
|
-
const t = schema.tables[tableName]
|
|
302
|
-
|
|
303
|
-
`),
|
|
304
|
-
|
|
305
|
-
lines.push(`
|
|
409
|
+
const t = schema.tables[tableName];
|
|
410
|
+
const colEntries = Object.entries(t.columns).map(([colName, col]) => ` ${colName}: ${serializeColumnBuilder(col)},`).join("\n");
|
|
411
|
+
const pkArgs = t.primaryKey.map(k => `'${k}'`).join(", ");
|
|
412
|
+
lines.push(`const ${tableName}Table = table('${t.name}')`);
|
|
413
|
+
lines.push(` .columns({`);
|
|
414
|
+
lines.push(colEntries);
|
|
415
|
+
lines.push(` })`);
|
|
416
|
+
lines.push(` .primaryKey(${pkArgs})`);
|
|
417
|
+
lines.push(``);
|
|
306
418
|
}
|
|
307
419
|
const relTableNames = Object.keys(schema.relationships).sort();
|
|
308
420
|
for (const tableName of relTableNames) {
|
|
309
|
-
const rels = schema.relationships[tableName]
|
|
310
|
-
|
|
421
|
+
const rels = schema.relationships[tableName];
|
|
422
|
+
const relEntries = Object.entries(rels);
|
|
311
423
|
if (relEntries.length === 0) continue;
|
|
312
424
|
const relBody = relEntries.map(([relName, hops]) => {
|
|
313
425
|
if (hops.length === 1) {
|
|
314
|
-
const hop = hops[0]
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
426
|
+
const hop = hops[0];
|
|
427
|
+
const fn = hop.cardinality === "one" ? "one" : "many";
|
|
428
|
+
const sf = hop.sourceField.map(f => `'${f}'`).join(", ");
|
|
429
|
+
const df = hop.destField.map(f => `'${f}'`).join(", ");
|
|
318
430
|
return ` ${relName}: ${fn}({
|
|
319
431
|
sourceField: [${sf}],
|
|
320
432
|
destSchema: ${hop.destSchema}Table,
|
|
@@ -322,61 +434,73 @@ function generateDrizzleSchemaFile(schema) {
|
|
|
322
434
|
})`;
|
|
323
435
|
}
|
|
324
436
|
const hopCode = hops.map(hop => {
|
|
325
|
-
const fn = hop.cardinality === "one" ? "one" : "many"
|
|
326
|
-
|
|
327
|
-
|
|
437
|
+
const fn = hop.cardinality === "one" ? "one" : "many";
|
|
438
|
+
const sf = hop.sourceField.map(f => `'${f}'`).join(", ");
|
|
439
|
+
const df = hop.destField.map(f => `'${f}'`).join(", ");
|
|
328
440
|
return `${fn}({ sourceField: [${sf}], destSchema: ${hop.destSchema}Table, destField: [${df}] })`;
|
|
329
441
|
}).join(", ");
|
|
330
442
|
return ` ${relName}: [${hopCode}]`;
|
|
331
|
-
}).join(
|
|
332
|
-
`);
|
|
333
|
-
lines.push(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
`);
|
|
339
|
-
|
|
340
|
-
`);
|
|
443
|
+
}).join(",\n");
|
|
444
|
+
lines.push(`const ${tableName}Relationships = relationships(${tableName}Table, ({ one, many }) => ({`);
|
|
445
|
+
lines.push(relBody);
|
|
446
|
+
lines.push(`}))`);
|
|
447
|
+
lines.push(``);
|
|
448
|
+
}
|
|
449
|
+
const tableList = tableNames.map(n => ` ${n}Table,`).join("\n");
|
|
450
|
+
const relList = relTableNames.filter(n => Object.keys(schema.relationships[n]).length > 0).map(n => ` ${n}Relationships,`).join("\n");
|
|
451
|
+
lines.push(`export const schema = createSchema({`);
|
|
452
|
+
lines.push(` tables: [`);
|
|
453
|
+
lines.push(tableList);
|
|
454
|
+
lines.push(` ],`);
|
|
455
|
+
lines.push(` relationships: [`);
|
|
456
|
+
lines.push(relList);
|
|
457
|
+
lines.push(` ],`);
|
|
458
|
+
lines.push(`})`);
|
|
459
|
+
lines.push(``);
|
|
460
|
+
return lines.join("\n");
|
|
341
461
|
}
|
|
342
462
|
async function generate(options) {
|
|
343
463
|
const {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
existsSync(generatedDir)
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
464
|
+
dir,
|
|
465
|
+
after,
|
|
466
|
+
silent
|
|
467
|
+
} = options;
|
|
468
|
+
const baseDir = resolve(dir);
|
|
469
|
+
const mutationsDir = resolve(baseDir, "mutations");
|
|
470
|
+
const usesMutationsDir = existsSync(mutationsDir);
|
|
471
|
+
const modelsDir = usesMutationsDir ? mutationsDir : resolve(baseDir, "models");
|
|
472
|
+
const modelsDirName = usesMutationsDir ? "mutations" : "models";
|
|
473
|
+
const generatedDir = resolve(baseDir, "generated");
|
|
474
|
+
const queriesDir = resolve(baseDir, "queries");
|
|
475
|
+
if (!existsSync(generatedDir)) {
|
|
476
|
+
mkdirSync(generatedDir, {
|
|
477
|
+
recursive: true
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
loadCache();
|
|
481
|
+
const allModelFiles = readdirSync(modelsDir).filter(f => f.endsWith(".ts")).sort();
|
|
482
|
+
const filesWithSchema = allModelFiles.filter(f => readFileSync(resolve(modelsDir, f), "utf-8").includes("export const schema = table("));
|
|
483
|
+
const allModelNames = allModelFiles.map(f => basename(f, ".ts"));
|
|
484
|
+
const schemaModelNames = filesWithSchema.map(f => basename(f, ".ts"));
|
|
485
|
+
const writeResults = [writeFileIfChanged(resolve(generatedDir, "models.ts"), generateModelsFile(allModelNames, modelsDirName)),
|
|
486
|
+
// only generate types.ts and tables.ts when model files define schemas.
|
|
487
|
+
// when using drizzle-zero CLI for schema generation, these files are
|
|
488
|
+
// managed externally and should not be overwritten.
|
|
489
|
+
...(filesWithSchema.length > 0 ? [writeFileIfChanged(resolve(generatedDir, "types.ts"), generateTypesFile(schemaModelNames)), writeFileIfChanged(resolve(generatedDir, "tables.ts"), generateTablesFile(schemaModelNames, modelsDirName))] : []), writeFileIfChanged(resolve(generatedDir, "README.md"), generateReadmeFile())];
|
|
490
|
+
let filesChanged = writeResults.filter(Boolean).length;
|
|
491
|
+
let queryCount = 0;
|
|
492
|
+
let mutationCount = 0;
|
|
493
|
+
const ts = await import("typescript");
|
|
494
|
+
const typeToValibot = paramType => {
|
|
495
|
+
try {
|
|
496
|
+
return parseTypeString(paramType.trim());
|
|
497
|
+
} catch {
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
};
|
|
377
501
|
if (existsSync(queriesDir)) {
|
|
378
|
-
const queryFiles = readdirSync(queriesDir).filter(f => f.endsWith(".ts"))
|
|
379
|
-
|
|
502
|
+
const queryFiles = readdirSync(queriesDir).filter(f => f.endsWith(".ts"));
|
|
503
|
+
const allQueries = [];
|
|
380
504
|
let queryResolver = null;
|
|
381
505
|
const getQueryResolver = () => {
|
|
382
506
|
if (!queryResolver) {
|
|
@@ -389,14 +513,15 @@ async function generate(options) {
|
|
|
389
513
|
return queryResolver;
|
|
390
514
|
};
|
|
391
515
|
for (const file of queryFiles) {
|
|
392
|
-
const filePath = resolve(queriesDir, file)
|
|
393
|
-
|
|
516
|
+
const filePath = resolve(queriesDir, file);
|
|
517
|
+
const fileBaseName = basename(file, ".ts");
|
|
394
518
|
try {
|
|
395
|
-
const content = readFileSync(filePath, "utf-8")
|
|
396
|
-
|
|
519
|
+
const content = readFileSync(filePath, "utf-8");
|
|
520
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
397
521
|
ts.forEachChild(sourceFile, node => {
|
|
398
522
|
if (ts.isVariableStatement(node)) {
|
|
399
|
-
|
|
523
|
+
const exportModifier = node.modifiers?.find(m => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
524
|
+
if (!exportModifier) return;
|
|
400
525
|
const declaration = node.declarationList.declarations[0];
|
|
401
526
|
if (!declaration || !ts.isVariableDeclaration(declaration)) return;
|
|
402
527
|
const name = declaration.name.getText(sourceFile);
|
|
@@ -404,40 +529,50 @@ async function generate(options) {
|
|
|
404
529
|
if (declaration.initializer && ts.isArrowFunction(declaration.initializer)) {
|
|
405
530
|
const params = declaration.initializer.parameters;
|
|
406
531
|
let paramType = "void";
|
|
407
|
-
params.length > 0
|
|
532
|
+
if (params.length > 0) {
|
|
533
|
+
const param = params[0];
|
|
534
|
+
paramType = param.type?.getText(sourceFile) || "unknown";
|
|
535
|
+
}
|
|
408
536
|
let valibotCode = typeToValibot(paramType);
|
|
409
537
|
if (!valibotCode && params.length > 0 && params[0].type) {
|
|
410
|
-
const resolver = getQueryResolver()
|
|
411
|
-
|
|
538
|
+
const resolver = getQueryResolver();
|
|
539
|
+
const resolverSourceFile = resolver.program.getSourceFile(filePath);
|
|
412
540
|
if (resolverSourceFile) {
|
|
413
541
|
const resolvedType = resolveParamType(ts, resolver, resolverSourceFile, name, 0);
|
|
414
|
-
|
|
542
|
+
if (resolvedType) {
|
|
543
|
+
valibotCode = resolver.typeToValibot(resolvedType);
|
|
544
|
+
}
|
|
415
545
|
}
|
|
416
546
|
}
|
|
417
|
-
valibotCode
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
547
|
+
if (valibotCode) {
|
|
548
|
+
allQueries.push({
|
|
549
|
+
name,
|
|
550
|
+
params: paramType,
|
|
551
|
+
valibotCode,
|
|
552
|
+
sourceFile: fileBaseName
|
|
553
|
+
});
|
|
554
|
+
} else if (!silent && paramType !== "void") {
|
|
555
|
+
console.error(`\u2717 ${name}: could not resolve type "${paramType}"`);
|
|
556
|
+
}
|
|
423
557
|
}
|
|
424
558
|
}
|
|
425
559
|
});
|
|
426
560
|
} catch (err) {
|
|
427
|
-
silent
|
|
561
|
+
if (!silent) console.error(`Error processing ${file}:`, err);
|
|
428
562
|
}
|
|
429
563
|
}
|
|
430
564
|
queryCount = allQueries.length;
|
|
431
|
-
const groupedChanged = writeFileIfChanged(resolve(generatedDir, "groupedQueries.ts"), generateGroupedQueriesFile(allQueries))
|
|
432
|
-
|
|
433
|
-
groupedChanged
|
|
565
|
+
const groupedChanged = writeFileIfChanged(resolve(generatedDir, "groupedQueries.ts"), generateGroupedQueriesFile(allQueries));
|
|
566
|
+
const syncedChanged = writeFileIfChanged(resolve(generatedDir, "syncedQueries.ts"), generateSyncedQueriesFile(allQueries));
|
|
567
|
+
if (groupedChanged) filesChanged++;
|
|
568
|
+
if (syncedChanged) filesChanged++;
|
|
434
569
|
}
|
|
435
|
-
const allModelMutations = []
|
|
436
|
-
|
|
437
|
-
|
|
570
|
+
const allModelMutations = [];
|
|
571
|
+
const mutationFiles = [];
|
|
572
|
+
const unresolvedModels = [];
|
|
438
573
|
for (const file of allModelFiles) {
|
|
439
|
-
const filePath = resolve(modelsDir, file)
|
|
440
|
-
|
|
574
|
+
const filePath = resolve(modelsDir, file);
|
|
575
|
+
const fileBaseName = basename(file, ".ts");
|
|
441
576
|
try {
|
|
442
577
|
const content = readFileSync(filePath, "utf-8");
|
|
443
578
|
mutationFiles.push({
|
|
@@ -445,32 +580,43 @@ async function generate(options) {
|
|
|
445
580
|
content,
|
|
446
581
|
baseName: fileBaseName
|
|
447
582
|
});
|
|
448
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest,
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
583
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
584
|
+
const result = extractMutationsFromModel(ts, sourceFile, content, filePath, !!silent, typeToValibot);
|
|
585
|
+
if (result) {
|
|
586
|
+
result.modelName = fileBaseName;
|
|
587
|
+
allModelMutations.push(result);
|
|
588
|
+
const hasUnresolved = result.custom.some(m => m.paramType !== "void" && m.paramType !== "unknown" && !m.valibotCode);
|
|
589
|
+
if (hasUnresolved) {
|
|
590
|
+
unresolvedModels.push({
|
|
591
|
+
baseName: fileBaseName,
|
|
592
|
+
filePath
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}
|
|
454
596
|
} catch (err) {
|
|
455
|
-
silent
|
|
597
|
+
if (!silent) console.error(`Error extracting mutations from ${file}:`, err);
|
|
456
598
|
}
|
|
457
599
|
}
|
|
458
600
|
if (unresolvedModels.length > 0) {
|
|
459
601
|
const collectTsFiles = dir2 => {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
602
|
+
const results = [];
|
|
603
|
+
for (const entry of readdirSync(dir2, {
|
|
604
|
+
withFileTypes: true
|
|
605
|
+
})) {
|
|
606
|
+
const fullPath = resolve(dir2, entry.name);
|
|
607
|
+
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
608
|
+
results.push(...collectTsFiles(fullPath));
|
|
609
|
+
} else if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
|
|
610
|
+
results.push({
|
|
466
611
|
path: fullPath,
|
|
467
612
|
content: readFileSync(fullPath, "utf-8")
|
|
468
613
|
});
|
|
469
614
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
615
|
+
}
|
|
616
|
+
return results;
|
|
617
|
+
};
|
|
618
|
+
const allFiles = collectTsFiles(baseDir);
|
|
619
|
+
const modelResolver = createTypeResolver(ts, allFiles, baseDir);
|
|
474
620
|
for (const {
|
|
475
621
|
baseName,
|
|
476
622
|
filePath
|
|
@@ -479,18 +625,28 @@ async function generate(options) {
|
|
|
479
625
|
if (!resolverSourceFile) continue;
|
|
480
626
|
const resolvedTypes = resolveMutationParamTypes(ts, modelResolver, resolverSourceFile);
|
|
481
627
|
if (resolvedTypes.size === 0) continue;
|
|
482
|
-
const content = readFileSync(filePath, "utf-8")
|
|
483
|
-
|
|
484
|
-
|
|
628
|
+
const content = readFileSync(filePath, "utf-8");
|
|
629
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
630
|
+
const result = extractMutationsFromModel(ts, sourceFile, content, filePath, !!silent, typeToValibot, resolvedTypes, modelResolver.typeToValibot);
|
|
485
631
|
if (result) {
|
|
486
632
|
result.modelName = baseName;
|
|
487
633
|
const idx = allModelMutations.findIndex(m => m.modelName === baseName);
|
|
488
|
-
idx >= 0
|
|
634
|
+
if (idx >= 0) allModelMutations[idx] = result;
|
|
489
635
|
}
|
|
490
636
|
}
|
|
491
637
|
}
|
|
492
|
-
for (const model of allModelMutations)
|
|
493
|
-
|
|
638
|
+
for (const model of allModelMutations) {
|
|
639
|
+
if (model.hasCRUD) mutationCount += 3;
|
|
640
|
+
mutationCount += model.custom.filter(m => !model.hasCRUD || !["insert", "update", "delete", "upsert"].includes(m.name)).length;
|
|
641
|
+
}
|
|
642
|
+
if (allModelMutations.length > 0) {
|
|
643
|
+
const mutationsChanged = writeFileIfChanged(resolve(generatedDir, "syncedMutations.ts"), generateSyncedMutationsFile(allModelMutations));
|
|
644
|
+
if (mutationsChanged) filesChanged++;
|
|
645
|
+
}
|
|
646
|
+
if (filesChanged > 0 && !silent) {
|
|
647
|
+
console.info(`\u2713 ${allModelFiles.length} models (${filesWithSchema.length} schemas)${queryCount ? `, ${queryCount} queries` : ""}${mutationCount ? `, ${mutationCount} mutations` : ""}`);
|
|
648
|
+
}
|
|
649
|
+
if (filesChanged > 0 && after) {
|
|
494
650
|
const {
|
|
495
651
|
execSync
|
|
496
652
|
} = await import("node:child_process");
|
|
@@ -503,10 +659,11 @@ async function generate(options) {
|
|
|
503
659
|
}
|
|
504
660
|
});
|
|
505
661
|
} catch (err) {
|
|
506
|
-
silent
|
|
662
|
+
if (!silent) console.error(`Error running after command: ${err}`);
|
|
507
663
|
}
|
|
508
664
|
}
|
|
509
|
-
|
|
665
|
+
saveCache();
|
|
666
|
+
return {
|
|
510
667
|
filesChanged,
|
|
511
668
|
modelCount: allModelFiles.length,
|
|
512
669
|
schemaCount: filesWithSchema.length,
|
|
@@ -516,36 +673,41 @@ async function generate(options) {
|
|
|
516
673
|
}
|
|
517
674
|
async function watch(options) {
|
|
518
675
|
const {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
676
|
+
dir,
|
|
677
|
+
debounce = 1e3
|
|
678
|
+
} = options;
|
|
679
|
+
const baseDir = resolve(dir);
|
|
680
|
+
const mutationsDir = resolve(baseDir, "mutations");
|
|
681
|
+
const modelsDir = existsSync(mutationsDir) ? mutationsDir : resolve(baseDir, "models");
|
|
682
|
+
const queriesDir = resolve(baseDir, "queries");
|
|
683
|
+
const generatedDir = resolve(baseDir, "generated");
|
|
527
684
|
await generate({
|
|
528
685
|
...options,
|
|
529
|
-
silent:
|
|
530
|
-
})
|
|
531
|
-
|
|
686
|
+
silent: true
|
|
687
|
+
});
|
|
688
|
+
console.info("\u{1F440} watching...\n");
|
|
532
689
|
const chokidar = await import("chokidar");
|
|
533
690
|
let debounceTimer = null;
|
|
534
691
|
const debouncedRegenerate = (path, event) => {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
692
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
693
|
+
console.info(`
|
|
694
|
+
${event} ${path}`);
|
|
695
|
+
debounceTimer = setTimeout(() => {
|
|
696
|
+
generate({
|
|
697
|
+
...options,
|
|
698
|
+
silent: false
|
|
699
|
+
});
|
|
700
|
+
}, debounce);
|
|
701
|
+
};
|
|
702
|
+
const watcher = chokidar.watch([modelsDir, queriesDir], {
|
|
703
|
+
persistent: true,
|
|
704
|
+
ignoreInitial: true,
|
|
705
|
+
ignored: [generatedDir]
|
|
706
|
+
});
|
|
707
|
+
watcher.on("change", path => debouncedRegenerate(path, "\u{1F4DD}"));
|
|
708
|
+
watcher.on("add", path => debouncedRegenerate(path, "\u2795"));
|
|
709
|
+
watcher.on("unlink", path => debouncedRegenerate(path, "\u{1F5D1}\uFE0F "));
|
|
710
|
+
return watcher;
|
|
549
711
|
}
|
|
550
712
|
export { generate, generateDrizzleSchemaFile, watch };
|
|
551
713
|
//# sourceMappingURL=generate.mjs.map
|