on-zero 0.9.7 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cjs/generate-helpers.test.cjs +0 -38
  2. package/dist/cjs/generate-helpers.test.native.js +0 -38
  3. package/dist/cjs/generate-helpers.test.native.js.map +1 -1
  4. package/dist/cjs/generate-lite.test.cjs +0 -522
  5. package/dist/cjs/generate-lite.test.native.js +0 -525
  6. package/dist/cjs/generate-lite.test.native.js.map +1 -1
  7. package/dist/cjs/generate.test.cjs +0 -691
  8. package/dist/cjs/generate.test.native.js +0 -691
  9. package/dist/cjs/generate.test.native.js.map +1 -1
  10. package/dist/cjs/mutations.test.cjs +0 -11
  11. package/dist/cjs/mutations.test.native.js +0 -18
  12. package/dist/cjs/mutations.test.native.js.map +1 -1
  13. package/dist/cjs/server.test.cjs +0 -93
  14. package/dist/cjs/server.test.native.js +0 -101
  15. package/dist/cjs/server.test.native.js.map +1 -1
  16. package/dist/cjs/serverWhere.test.cjs +0 -45
  17. package/dist/cjs/serverWhere.test.native.js +0 -51
  18. package/dist/cjs/serverWhere.test.native.js.map +1 -1
  19. package/dist/esm/generate-helpers.test.mjs +1 -39
  20. package/dist/esm/generate-helpers.test.mjs.map +1 -1
  21. package/dist/esm/generate-helpers.test.native.js +1 -39
  22. package/dist/esm/generate-helpers.test.native.js.map +1 -1
  23. package/dist/esm/generate-lite.test.mjs +0 -522
  24. package/dist/esm/generate-lite.test.mjs.map +1 -1
  25. package/dist/esm/generate-lite.test.native.js +0 -525
  26. package/dist/esm/generate-lite.test.native.js.map +1 -1
  27. package/dist/esm/generate.test.mjs +2 -668
  28. package/dist/esm/generate.test.mjs.map +1 -1
  29. package/dist/esm/generate.test.native.js +2 -668
  30. package/dist/esm/generate.test.native.js.map +1 -1
  31. package/dist/esm/mutations.test.mjs +0 -11
  32. package/dist/esm/mutations.test.mjs.map +1 -1
  33. package/dist/esm/mutations.test.native.js +0 -18
  34. package/dist/esm/mutations.test.native.js.map +1 -1
  35. package/dist/esm/server.test.mjs +0 -93
  36. package/dist/esm/server.test.mjs.map +1 -1
  37. package/dist/esm/server.test.native.js +0 -101
  38. package/dist/esm/server.test.native.js.map +1 -1
  39. package/dist/esm/serverWhere.test.mjs +0 -45
  40. package/dist/esm/serverWhere.test.mjs.map +1 -1
  41. package/dist/esm/serverWhere.test.native.js +0 -51
  42. package/dist/esm/serverWhere.test.native.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/generate-helpers.test.ts +0 -40
  45. package/src/generate-lite.test.ts +0 -586
  46. package/src/generate.test.ts +0 -844
  47. package/src/mutations.test.ts +0 -21
  48. package/src/server.test.ts +0 -75
  49. package/src/serverWhere.test.ts +0 -42
@@ -19,36 +19,6 @@ function expectNoDuplicates(source) {
19
19
  return names;
20
20
  }
21
21
  (0, import_vitest.describe)("generated module identifiers", () => {
22
- (0, import_vitest.test)("grouped queries keep distinct aliases when one namespace is another plus Source", () => {
23
- const source = (0, import_generate_helpers.generateGroupedQueriesFile)([{
24
- name: "appById",
25
- sourceFile: "app",
26
- importPath: "../app/queries"
27
- }, {
28
- name: "appSourceByAppId",
29
- sourceFile: "appSource",
30
- importPath: "../appSource/queries"
31
- }]);
32
- expectNoDuplicates(source);
33
- const appExport = source.match(/export const app = \{([^}]*)\}/)[1];
34
- const appSourceExport = source.match(/export const appSource = \{([^}]*)\}/)[1];
35
- (0, import_vitest.expect)(appExport).toContain("appById");
36
- (0, import_vitest.expect)(appSourceExport).toContain("appSourceByAppId");
37
- (0, import_vitest.expect)(appExport).not.toContain("appSourceByAppId");
38
- });
39
- (0, import_vitest.test)("models keep distinct aliases when user and userPublic both exist", () => {
40
- const source = (0, import_generate_helpers.generateModelsFile)([{
41
- name: "user",
42
- importPath: "../user"
43
- }, {
44
- name: "userPublic",
45
- importPath: "../userPublic"
46
- }]);
47
- expectNoDuplicates(source);
48
- const modelsObject = source.match(/export const models = \{([\s\S]*)\}/)[1];
49
- (0, import_vitest.expect)(modelsObject).toMatch(/\buser:/);
50
- (0, import_vitest.expect)(modelsObject).toMatch(/\buserPublic\b/);
51
- });
52
22
  (0, import_vitest.test)("table re-exports keep distinct names when user and userPublic both exist", () => {
53
23
  const source = (0, import_generate_helpers.generateTablesFile)([{
54
24
  name: "user",
@@ -59,12 +29,4 @@ function expectNoDuplicates(source) {
59
29
  }]);
60
30
  expectNoDuplicates(source);
61
31
  });
62
- (0, import_vitest.test)("a namespace with no collision keeps its plain alias", () => {
63
- const source = (0, import_generate_helpers.generateGroupedQueriesFile)([{
64
- name: "todoById",
65
- sourceFile: "todo",
66
- importPath: "../todo/queries"
67
- }]);
68
- (0, import_vitest.expect)(source).toContain(`import * as todoSource from '../todo/queries'`);
69
- });
70
32
  });
@@ -42,36 +42,6 @@ function expectNoDuplicates(source) {
42
42
  return names;
43
43
  }
44
44
  (0, import_vitest.describe)("generated module identifiers", function () {
45
- (0, import_vitest.test)("grouped queries keep distinct aliases when one namespace is another plus Source", function () {
46
- var source = (0, import_generate_helpers.generateGroupedQueriesFile)([{
47
- name: "appById",
48
- sourceFile: "app",
49
- importPath: "../app/queries"
50
- }, {
51
- name: "appSourceByAppId",
52
- sourceFile: "appSource",
53
- importPath: "../appSource/queries"
54
- }]);
55
- expectNoDuplicates(source);
56
- var appExport = source.match(/export const app = \{([^}]*)\}/)[1];
57
- var appSourceExport = source.match(/export const appSource = \{([^}]*)\}/)[1];
58
- (0, import_vitest.expect)(appExport).toContain("appById");
59
- (0, import_vitest.expect)(appSourceExport).toContain("appSourceByAppId");
60
- (0, import_vitest.expect)(appExport).not.toContain("appSourceByAppId");
61
- });
62
- (0, import_vitest.test)("models keep distinct aliases when user and userPublic both exist", function () {
63
- var source = (0, import_generate_helpers.generateModelsFile)([{
64
- name: "user",
65
- importPath: "../user"
66
- }, {
67
- name: "userPublic",
68
- importPath: "../userPublic"
69
- }]);
70
- expectNoDuplicates(source);
71
- var modelsObject = source.match(/export const models = \{([\s\S]*)\}/)[1];
72
- (0, import_vitest.expect)(modelsObject).toMatch(/\buser:/);
73
- (0, import_vitest.expect)(modelsObject).toMatch(/\buserPublic\b/);
74
- });
75
45
  (0, import_vitest.test)("table re-exports keep distinct names when user and userPublic both exist", function () {
76
46
  var source = (0, import_generate_helpers.generateTablesFile)([{
77
47
  name: "user",
@@ -82,13 +52,5 @@ function expectNoDuplicates(source) {
82
52
  }]);
83
53
  expectNoDuplicates(source);
84
54
  });
85
- (0, import_vitest.test)("a namespace with no collision keeps its plain alias", function () {
86
- var source = (0, import_generate_helpers.generateGroupedQueriesFile)([{
87
- name: "todoById",
88
- sourceFile: "todo",
89
- importPath: "../todo/queries"
90
- }]);
91
- (0, import_vitest.expect)(source).toContain(`import * as todoSource from '../todo/queries'`);
92
- });
93
55
  });
94
56
  //# sourceMappingURL=generate-helpers.test.native.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["import_vitest","require","import_generate_helpers","declaredIdentifiers","source","names","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","split","Symbol","iterator","_step","next","done","line","value","imported","match","push","declared","reexported","err","return","expectNoDuplicates","duplicates","filter","name","index","indexOf","expect","toEqual","describe","test","generateGroupedQueriesFile","sourceFile","importPath","appExport","appSourceExport","toContain","not"],"sources":["../../src/generate-helpers.test.ts"],"sourcesContent":[null],"mappings":"AAAA;;AAEA,IAAAA,aAAA,GAAAC,OAAA,SAIO;AAKP,IAAAC,uBAAS,GAAoBD,OAA0B;AACrD,SAAME,mBAAmBA,CAAAC,MAAA;EACzB,IAAAC,KAAA,GAAW;EACT,IAAAC,yBAAsB,GAAM;IAAAC,iBAAA,QAA8B;IAAAC,cAAA;EAC1D;IACA,SAAMC,SAAW,GAAAL,MAAK,CAAMM,KAAA,OAAAC,MAAA,CAAAC,QAA2B,KAAAC,KAAA,IAAAP,yBAAA,IAAAO,KAAA,GAAAJ,SAAA,CAAAK,IAAA,IAAAC,IAAA,GAAAT,yBAAA;MACvD,IAAIU,IAAA,GAAUH,KAAA,CAAAI,KAAM;MACpB,IAAMC,QAAA,GAAAF,IAAa,CAAAG,KAAK,+BAAM;MAC9B,IAAID,QAAA,EAAYb,KAAA,CAAMe,IAAA,CAAKF,QAAA,GAAW,CAAC;MACzC,IAAAG,QAAA,GAAAL,IAAA,CAAAG,KAAA;MACA,IAAOE,QAAA,EAAAhB,KAAA,CAAAe,IAAA,CAAAC,QAAA;MACT,IAAAC,UAAA,GAAAN,IAAA,CAAAG,KAAA;MAEA,IAASG,UAAA,EAAAjB,KAAA,CAAmBe,IAAA,CAAAE,UAAgB;IAC1C;EACA,SAAMC,GAAA;IACNhB,iBAAA,OAAO;IACPC,cAAO,GAAAe,GAAA;EACT;IAEA;MACE,KAAAjB,yBAAK,IAAAG,SAAA,CAAAe,MAAA;QACHf,SAAM,CAAAe,MAAS;MACb;IAAmE,UACnE;MAAA,IACEjB,iBAAM;QACN,MAAAC,cAAY;MAAA;IACA;EACd;EAGF,OAAAH,KAAA;AAEA;AACA,SAAAoB,kBAAMA,CAAkBrB,MAAA,EAAO;EAC/B,IAAAC,KAAA,GAAAF,mBAAO,CAAAC,MAAS,CAAE;EAClB,IAAAsB,UAAA,GAAArB,KAAA,CAAAsB,MAAO,WAAAC,IAAe,EAAEC,KAAA;IACxB,OAAAxB,KAAA,CAAAyB,OAAA,CAAAF,IAAA,CAAO,KAAAC,KAAS;EAClB,CAAC;EAED,IAAA7B,aAAA,CAAA+B,MAAK,EAAAL,UAAA,EAAAM,OAAA;EACH,OAAA3B,KAAM;AAA4B;AACM,IAAAL,aAC9B,CAAAiC,QAAA,EAAc,8BAA4B;EAAA,EACpD,EAA6CjC,aAAA,CAAAkC,IAAA;IAE7C,IAAA9B,MAAA,OAAAF,uBAAyB,CAAAiC,0BAAA,GAEzB;MACAP,IAAA;MACAQ,UAAA;MACDC,UAAA;IAED,GACE;MACIT,IAAA,EAAM,kBAAQ;MACdQ,UAAM,aAAc;MACqBC,UAAA;IAE7C,EACD;IAEDZ,kBAAA,CAAArB,MAAK;IACH,IAAAkC,SAAM,GAAAlC,MAAS,CAAAe,KAAA;IAA2B,IACtCoB,eAAM,GAAYnC,MAAA,CAAAe,KAAY,uCAAsC;IACxE,CAAC,GAAAnB,aAAA,CAAA+B,MAAA,EAAAO,SAAA,EAAAE,SAAA;IAED,IAAAxC,aAAA,CAAA+B,MAAA,EAAOQ,eAAQ,EAAAC,SAAU;IAC1B,IAAAxC,aAAA,CAAA+B,MAAA,EAAAO,SAAA,EAAAG,GAAA,CAAAD,SAAA;EACF","ignoreList":[]}
1
+ {"version":3,"names":["import_vitest","require","import_generate_helpers","declaredIdentifiers","source","names","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","split","Symbol","iterator","_step","next","done","line","value","imported","match","push","declared","reexported","err","return"],"sources":["../../src/generate-helpers.test.ts"],"sourcesContent":[null],"mappings":"AAAA;;AAEA,IAAAA,aAAA,GAAAC,OAAA,SAIO;AAKP,IAAAC,uBAAS,GAAoBD,OAA0B;AACrD,SAAME,mBAAmBA,CAAAC,MAAA;EACzB,IAAAC,KAAA,GAAW;EACT,IAAAC,yBAAsB,GAAM;IAAAC,iBAAA,QAA8B;IAAAC,cAAA;EAC1D;IACA,SAAMC,SAAW,GAAAL,MAAK,CAAMM,KAAA,OAAAC,MAAA,CAAAC,QAA2B,KAAAC,KAAA,IAAAP,yBAAA,IAAAO,KAAA,GAAAJ,SAAA,CAAAK,IAAA,IAAAC,IAAA,GAAAT,yBAAA;MACvD,IAAIU,IAAA,GAAUH,KAAA,CAAAI,KAAM;MACpB,IAAMC,QAAA,GAAAF,IAAa,CAAAG,KAAK,+BAAM;MAC9B,IAAID,QAAA,EAAYb,KAAA,CAAMe,IAAA,CAAKF,QAAA,GAAW,CAAC;MACzC,IAAAG,QAAA,GAAAL,IAAA,CAAAG,KAAA;MACA,IAAOE,QAAA,EAAAhB,KAAA,CAAAe,IAAA,CAAAC,QAAA;MACT,IAAAC,UAAA,GAAAN,IAAA,CAAAG,KAAA;MAEA,IAASG,UAAA,EAAAjB,KAAA,CAAmBe,IAAA,CAAAE,UAAgB;IAC1C;EACA,SAAMC,GAAA;IACNhB,iBAAA,OAAO;IACPC,cAAO,GAAAe,GAAA;EACT;IAEA;MACE,KAAAjB,yBAAK,IAAAG,SAAA,CAAAe,MAAA;QACHf,SAAM,CAAAe,MAAS;MACb;IAAsC,UAC9B;MACmC,IAAAjB,iBAAA;QAE7C,MAAAC,cAAmB;MACpB;IACF","ignoreList":[]}
@@ -15,391 +15,6 @@ const DIR = "/proj/src/data";
15
15
  import_vitest.vi.restoreAllMocks();
16
16
  });
17
17
  (0, import_vitest.describe)("generateLite", () => {
18
- (0, import_vitest.test)("emits models.ts, syncedMutations.ts, and README.md from inline types", () => {
19
- const files = {
20
- [`${DIR}/todo.ts`]: "// fake source, parser returns fixture",
21
- [`${DIR}/user.ts`]: "// fake source, parser returns fixture"
22
- };
23
- const fixtures = {
24
- [`${DIR}/todo.ts`]: {
25
- mutations: [{
26
- modelName: "todo",
27
- handlers: [{
28
- name: "toggle",
29
- paramTypeText: "{ id: string; isActive: boolean }"
30
- }, {
31
- name: "rename",
32
- paramTypeText: "{ id: string; title: string }"
33
- }],
34
- schema: null
35
- }],
36
- queries: []
37
- },
38
- [`${DIR}/user.ts`]: {
39
- mutations: [{
40
- modelName: "user",
41
- handlers: [{
42
- name: "finishOnboarding",
43
- // null = no second param / void
44
- paramTypeText: null
45
- }],
46
- schema: null
47
- }],
48
- queries: []
49
- }
50
- };
51
- const result = (0, import_generate_lite.generateLite)({
52
- files,
53
- dir: DIR,
54
- parse: makeParse(fixtures)
55
- });
56
- (0, import_vitest.expect)(Object.keys(result.files).sort()).toEqual(["README.md", "groupedQueries.ts", "instances.ts", "models.ts", "syncedMutations.ts", "syncedQueries.ts"]);
57
- const models = result.files["models.ts"];
58
- (0, import_vitest.expect)(models).toContain("import * as todo from '../todo'");
59
- (0, import_vitest.expect)(models).toContain("import * as userPublic from '../user'");
60
- (0, import_vitest.expect)(models).toContain("user: userPublic,");
61
- (0, import_vitest.expect)(models).not.toContain("\n userPublic,");
62
- (0, import_vitest.expect)(models).toContain("export const models = {");
63
- const syncedMutations = result.files["syncedMutations.ts"];
64
- (0, import_vitest.expect)(syncedMutations).toContain("toggle:");
65
- (0, import_vitest.expect)(syncedMutations).toContain("v.object({");
66
- (0, import_vitest.expect)(syncedMutations).toContain("id: v.string()");
67
- (0, import_vitest.expect)(syncedMutations).toContain("isActive: v.boolean()");
68
- (0, import_vitest.expect)(syncedMutations).toContain("rename:");
69
- (0, import_vitest.expect)(syncedMutations).toContain("title: v.string()");
70
- (0, import_vitest.expect)(syncedMutations).toContain("finishOnboarding: v.void_()");
71
- (0, import_vitest.expect)(result.modelCount).toBe(2);
72
- (0, import_vitest.expect)(result.schemaCount).toBe(0);
73
- (0, import_vitest.expect)(result.mutationCount).toBe(3);
74
- });
75
- (0, import_vitest.test)("parses newline-separated mutation object types", () => {
76
- const files = {
77
- [`${DIR}/agentEvent.ts`]: "// fake",
78
- [`${DIR}/deployment.ts`]: "// fake"
79
- };
80
- const fixtures = {
81
- [`${DIR}/agentEvent.ts`]: {
82
- mutations: [{
83
- modelName: "agentEvent",
84
- handlers: [{
85
- name: "claimReviewLease",
86
- paramTypeText: `{
87
- id: string
88
- projectId: string
89
- createdAt: number
90
- }`
91
- }],
92
- schema: null
93
- }],
94
- queries: []
95
- },
96
- [`${DIR}/deployment.ts`]: {
97
- mutations: [{
98
- modelName: "deployment",
99
- handlers: [{
100
- name: "deploy",
101
- paramTypeText: `{
102
- id: string
103
- platform?: string // 'web' | 'ios'
104
- buildTier?: string // 'dev' | 'testflight' | 'production'
105
- }`
106
- }],
107
- schema: null
108
- }],
109
- queries: []
110
- }
111
- };
112
- const result = (0, import_generate_lite.generateLite)({
113
- files,
114
- dir: DIR,
115
- parse: makeParse(fixtures)
116
- });
117
- const synced = result.files["syncedMutations.ts"];
118
- (0, import_vitest.expect)(synced).toContain("claimReviewLease:");
119
- (0, import_vitest.expect)(synced).toContain("projectId: v.string()");
120
- (0, import_vitest.expect)(synced).toContain("createdAt: v.number()");
121
- (0, import_vitest.expect)(synced).toContain("deploy:");
122
- (0, import_vitest.expect)(synced).toContain("platform: v.optional(v.string())");
123
- (0, import_vitest.expect)(synced).toContain("buildTier: v.optional(v.string())");
124
- (0, import_vitest.expect)(synced).not.toContain("claimReviewLease: v.object({})");
125
- (0, import_vitest.expect)(synced).not.toContain("deploy: v.object({})");
126
- });
127
- (0, import_vitest.test)("parses object intersections and skips index signatures", () => {
128
- const files = {
129
- [`${DIR}/agent.ts`]: "// fake"
130
- };
131
- const fixtures = {
132
- [`${DIR}/agent.ts`]: {
133
- mutations: [{
134
- modelName: "agent",
135
- handlers: [{
136
- name: "update",
137
- paramTypeText: `{
138
- id: string
139
- } & {
140
- status?: string
141
- currentTaskId?: string
142
- [key: string]: unknown
143
- }`
144
- }],
145
- schema: null
146
- }],
147
- queries: []
148
- }
149
- };
150
- const result = (0, import_generate_lite.generateLite)({
151
- files,
152
- dir: DIR,
153
- parse: makeParse(fixtures)
154
- });
155
- const synced = result.files["syncedMutations.ts"];
156
- (0, import_vitest.expect)(synced).toContain("update:");
157
- (0, import_vitest.expect)(synced).toContain("id: v.string()");
158
- (0, import_vitest.expect)(synced).toContain("status: v.optional(v.string())");
159
- (0, import_vitest.expect)(synced).toContain("currentTaskId: v.optional(v.string())");
160
- (0, import_vitest.expect)(synced).not.toContain("[key");
161
- (0, import_vitest.expect)(synced).not.toContain("update: v.object({})");
162
- });
163
- (0, import_vitest.test)("falls back to v.unknown() for type references", () => {
164
- const files = {
165
- [`${DIR}/post.ts`]: `export const allPosts = () => zql.post`
166
- };
167
- const fixtures = {
168
- [`${DIR}/post.ts`]: {
169
- mutations: [{
170
- modelName: "post",
171
- handlers: [{
172
- name: "archive",
173
- // bare type reference — parseTypeString returns null, so
174
- // generate-lite should fall back to v.unknown() rather than
175
- // attempting cross-file type resolution.
176
- paramTypeText: "ArchiveParams"
177
- }, {
178
- name: "publish",
179
- // primitive, should resolve
180
- paramTypeText: "string"
181
- }],
182
- schema: null
183
- }],
184
- queries: []
185
- }
186
- };
187
- const result = (0, import_generate_lite.generateLite)({
188
- files,
189
- dir: DIR,
190
- parse: makeParse(fixtures)
191
- });
192
- const synced = result.files["syncedMutations.ts"];
193
- (0, import_vitest.expect)(synced).toContain("archive: v.unknown()");
194
- (0, import_vitest.expect)(synced).toContain("publish: v.string()");
195
- });
196
- (0, import_vitest.test)("uses v.unknown() for explicitly unknown mutation params", () => {
197
- const files = {
198
- [`${DIR}/project.ts`]: "// fake"
199
- };
200
- const fixtures = {
201
- [`${DIR}/project.ts`]: {
202
- mutations: [{
203
- modelName: "project",
204
- handlers: [{
205
- name: "insert",
206
- paramTypeText: "unknown"
207
- }],
208
- schema: null
209
- }],
210
- queries: []
211
- }
212
- };
213
- const result = (0, import_generate_lite.generateLite)({
214
- files,
215
- dir: DIR,
216
- parse: makeParse(fixtures)
217
- });
218
- (0, import_vitest.expect)(result.files["syncedMutations.ts"]).toContain("insert: v.unknown()");
219
- });
220
- (0, import_vitest.test)("emits query files with v.unknown() fallback for references", () => {
221
- const files = {
222
- [`${DIR}/post.ts`]: "// fake"
223
- };
224
- const fixtures = {
225
- [`${DIR}/post.ts`]: {
226
- mutations: [],
227
- queries: [
228
- // no-arg query → void
229
- {
230
- name: "allPosts",
231
- rootTable: "post",
232
- paramTypeText: null,
233
- relatedPaths: []
234
- },
235
- // inline object → real validator
236
- {
237
- name: "postById",
238
- rootTable: "post",
239
- paramTypeText: "{ id: string }",
240
- relatedPaths: []
241
- },
242
- // primitive
243
- {
244
- name: "byAuthorId",
245
- rootTable: "post",
246
- paramTypeText: "string",
247
- relatedPaths: []
248
- },
249
- // optional nullable inline object
250
- {
251
- name: "paged",
252
- rootTable: "post",
253
- paramTypeText: "{ pageSize: number; cursor?: { id: string; createdAt: number } | null }",
254
- relatedPaths: []
255
- },
256
- // type reference → fallback
257
- {
258
- name: "filtered",
259
- rootTable: "post",
260
- paramTypeText: "PostFilter",
261
- relatedPaths: []
262
- },
263
- // permission should be skipped
264
- {
265
- name: "permission",
266
- rootTable: "post",
267
- paramTypeText: null,
268
- relatedPaths: []
269
- }]
270
- }
271
- };
272
- const result = (0, import_generate_lite.generateLite)({
273
- files,
274
- dir: DIR,
275
- parse: makeParse(fixtures)
276
- });
277
- (0, import_vitest.expect)(result.files["groupedQueries.ts"]).toBeDefined();
278
- (0, import_vitest.expect)(result.files["syncedQueries.ts"]).toBeDefined();
279
- const grouped = result.files["groupedQueries.ts"];
280
- (0, import_vitest.expect)(grouped).toContain("import * as postSource from '../post'");
281
- (0, import_vitest.expect)(grouped).toContain("postById: postSource.postById");
282
- const synced = result.files["syncedQueries.ts"];
283
- (0, import_vitest.expect)(synced).toContain("allPosts: defineQuery(() => Queries.post.allPosts())");
284
- (0, import_vitest.expect)(synced).toContain("postById: defineQuery(");
285
- (0, import_vitest.expect)(synced).toContain("id: v.string()");
286
- (0, import_vitest.expect)(synced).toContain("byAuthorId: defineQuery(");
287
- (0, import_vitest.expect)(synced).toMatch(/byAuthorId: defineQuery\(\s*v\.string\(\)/);
288
- (0, import_vitest.expect)(synced).toContain("paged: defineQuery(");
289
- (0, import_vitest.expect)(synced).toContain("cursor: v.optional(v.nullable(v.object({");
290
- (0, import_vitest.expect)(synced).toContain("filtered: defineQuery(");
291
- (0, import_vitest.expect)(synced).toMatch(/filtered: defineQuery\(\s*v\.unknown\(\)/);
292
- (0, import_vitest.expect)(synced).not.toContain("permission: defineQuery");
293
- (0, import_vitest.expect)(result.queryCount).toBe(5);
294
- });
295
- (0, import_vitest.test)("emits types.ts and tables.ts when a model declares a schema inline", () => {
296
- const files = {
297
- [`${DIR}/task.ts`]: "// fake"
298
- };
299
- const fixtures = {
300
- [`${DIR}/task.ts`]: {
301
- mutations: [{
302
- modelName: "task",
303
- handlers: [],
304
- schema: {
305
- tableName: "task",
306
- primaryKeys: ["id"],
307
- columns: [{
308
- name: "id",
309
- builderText: "string()"
310
- }, {
311
- name: "title",
312
- builderText: "string()"
313
- }, {
314
- name: "priority",
315
- builderText: "number()"
316
- }, {
317
- name: "done",
318
- builderText: "boolean()"
319
- }, {
320
- name: "note",
321
- builderText: "string().optional()"
322
- }]
323
- }
324
- }],
325
- queries: []
326
- }
327
- };
328
- const result = (0, import_generate_lite.generateLite)({
329
- files,
330
- dir: DIR,
331
- parse: makeParse(fixtures)
332
- });
333
- (0, import_vitest.expect)(result.schemaCount).toBe(1);
334
- (0, import_vitest.expect)(result.files["types.ts"]).toBeDefined();
335
- (0, import_vitest.expect)(result.files["tables.ts"]).toBeDefined();
336
- const types = result.files["types.ts"];
337
- (0, import_vitest.expect)(types).toContain("export type Task = TableInsertRow<typeof schema.task>");
338
- const tables = result.files["tables.ts"];
339
- (0, import_vitest.expect)(tables).toContain("export { schema as task } from '../task'");
340
- const synced = result.files["syncedMutations.ts"];
341
- (0, import_vitest.expect)(synced).toContain("insert:");
342
- (0, import_vitest.expect)(synced).toContain("update:");
343
- (0, import_vitest.expect)(synced).toContain("delete:");
344
- (0, import_vitest.expect)(result.mutationCount).toBe(3);
345
- });
346
- (0, import_vitest.test)("ignores private files inside a namespace folder", () => {
347
- const files = {
348
- [`${DIR}/post/mutations.ts`]: "// fake",
349
- [`${DIR}/post/README.md`]: "not a model",
350
- [`${DIR}/post/helpers/util.ts`]: "private helper, ignored",
351
- [`${DIR}/post/post.d.ts`]: "declaration file, ignored",
352
- [`${DIR}/post/post.test.ts`]: "test file, ignored",
353
- [`${DIR}/post/post.spec.ts`]: "spec file, ignored"
354
- };
355
- const fixtures = {
356
- [`${DIR}/post/mutations.ts`]: {
357
- mutations: [{
358
- modelName: "post",
359
- handlers: [],
360
- schema: null
361
- }],
362
- queries: []
363
- }
364
- };
365
- const result = (0, import_generate_lite.generateLite)({
366
- files,
367
- dir: DIR,
368
- parse: makeParse(fixtures)
369
- });
370
- (0, import_vitest.expect)(result.modelCount).toBe(1);
371
- const models = result.files["models.ts"];
372
- (0, import_vitest.expect)(models).toContain("import * as post from '../post/mutations'");
373
- (0, import_vitest.expect)(models).not.toContain("util");
374
- (0, import_vitest.expect)(models).not.toContain("README");
375
- (0, import_vitest.expect)(models).not.toContain("post.test");
376
- (0, import_vitest.expect)(models).not.toContain("post.spec");
377
- });
378
- (0, import_vitest.test)("supports a split namespace folder", () => {
379
- const files = {
380
- [`${DIR}/post/mutations.ts`]: "// fake"
381
- };
382
- const fixtures = {
383
- [`${DIR}/post/mutations.ts`]: {
384
- mutations: [{
385
- modelName: "post",
386
- handlers: [{
387
- name: "publish",
388
- paramTypeText: "{ id: string }"
389
- }],
390
- schema: null
391
- }],
392
- queries: []
393
- }
394
- };
395
- const result = (0, import_generate_lite.generateLite)({
396
- files,
397
- dir: DIR,
398
- parse: makeParse(fixtures)
399
- });
400
- const models = result.files["models.ts"];
401
- (0, import_vitest.expect)(models).toContain("from '../post/mutations'");
402
- });
403
18
  (0, import_vitest.test)("derives single-file namespaces from data exports", () => {
404
19
  const files = {
405
20
  [`${DIR}/server.ts`]: `export const serverRows = () => zql.server`,
@@ -462,143 +77,6 @@ const DIR = "/proj/src/data";
462
77
  parse: makeParse({})
463
78
  })).toThrow(/removed top-level queries\/ layout/);
464
79
  });
465
- (0, import_vitest.test)("derives scoped related-table closure from lite metadata", () => {
466
- const files = {
467
- [`${DIR}/on-zero.config.ts`]: `export default defineConfig({ instances: { project: { scope: 'projectId' } } })`,
468
- [`${DIR}/project/message/queries.ts`]: `export const messages = () => zql.message.related('comments')`,
469
- [`${DIR}/project/message/mutations.ts`]: "// fake mutation",
470
- ["/proj/src/database/relations.ts"]: "// fake relations",
471
- ["/proj/src/database/schema.ts"]: "// fake tables"
472
- };
473
- const empty = {
474
- mutations: [],
475
- queries: []
476
- };
477
- const result = (0, import_generate_lite.generateLite)({
478
- files,
479
- dir: DIR,
480
- parse: makeParse({
481
- [`${DIR}/on-zero.config.ts`]: {
482
- ...empty,
483
- dataConfig: {
484
- instances: {
485
- project: {
486
- scope: "projectId"
487
- }
488
- }
489
- }
490
- },
491
- [`${DIR}/project/message/queries.ts`]: {
492
- ...empty,
493
- queries: [{
494
- name: "messages",
495
- rootTable: "message",
496
- paramTypeText: null,
497
- relatedPaths: [["comments", "author"]]
498
- }]
499
- },
500
- [`${DIR}/project/message/mutations.ts`]: {
501
- ...empty,
502
- mutations: [{
503
- modelName: "message",
504
- handlers: [],
505
- schema: {
506
- tableName: "message",
507
- primaryKeys: ["id"],
508
- columns: [{
509
- name: "id",
510
- builderText: "string()"
511
- }, {
512
- name: "projectId",
513
- builderText: "string()"
514
- }]
515
- }
516
- }]
517
- },
518
- "/proj/src/database/relations.ts": {
519
- ...empty,
520
- relations: [{
521
- sourceTable: "message",
522
- name: "comments",
523
- targetTable: "comment"
524
- }, {
525
- sourceTable: "comment",
526
- name: "author",
527
- targetTable: "userPublic"
528
- }]
529
- },
530
- "/proj/src/database/schema.ts": {
531
- ...empty,
532
- tables: [{
533
- name: "comment",
534
- columns: ["id", "projectId"]
535
- }, {
536
- name: "userPublic",
537
- columns: ["id", "projectId"]
538
- }]
539
- }
540
- })
541
- });
542
- (0, import_vitest.expect)(result.files["instances.ts"]).toContain('syncTables: ["comment","message","userPublic"]');
543
- const instance = result.instances.find(entry => entry.name === "project");
544
- (0, import_vitest.expect)(instance?.syncTables).toEqual(["comment", "message", "userPublic"]);
545
- (0, import_vitest.expect)(instance?.supportTables).toEqual([]);
546
- });
547
- (0, import_vitest.test)("derives query membership from the query root instead of its namespace", () => {
548
- const files = {
549
- [`${DIR}/category/mutations.ts`]: "// fake category model",
550
- [`${DIR}/dashboard/queries.ts`]: `export const monthSummary = () => zql.category.related('expenses')`,
551
- ["/proj/src/database/relations.ts"]: "// fake relations",
552
- ["/proj/src/database/schema.ts"]: "// fake tables"
553
- };
554
- const empty = {
555
- mutations: [],
556
- queries: []
557
- };
558
- const result = (0, import_generate_lite.generateLite)({
559
- files,
560
- dir: DIR,
561
- parse: makeParse({
562
- [`${DIR}/category/mutations.ts`]: {
563
- ...empty,
564
- mutations: [{
565
- modelName: "category",
566
- handlers: [],
567
- schema: null
568
- }]
569
- },
570
- [`${DIR}/dashboard/queries.ts`]: {
571
- ...empty,
572
- queries: [{
573
- name: "monthSummary",
574
- rootTable: "category",
575
- paramTypeText: null,
576
- relatedPaths: [["expenses"]]
577
- }]
578
- },
579
- "/proj/src/database/relations.ts": {
580
- ...empty,
581
- relations: [{
582
- sourceTable: "category",
583
- name: "expenses",
584
- targetTable: "expense"
585
- }]
586
- },
587
- "/proj/src/database/schema.ts": {
588
- ...empty,
589
- tables: [{
590
- name: "category",
591
- columns: ["id"]
592
- }, {
593
- name: "expense",
594
- columns: ["id", "categoryId"]
595
- }]
596
- }
597
- })
598
- });
599
- (0, import_vitest.expect)(result.instances[0]?.syncTables).toEqual(["category", "expense"]);
600
- (0, import_vitest.expect)(result.instances[0]?.syncTables).not.toContain("dashboard");
601
- });
602
80
  (0, import_vitest.test)("ignores related syntax mentioned only in a query-file comment", () => {
603
81
  const files = {
604
82
  [`${DIR}/dashboard/queries.ts`]: `// monthSummary moved to category/queries.ts because it uses .related()`